Reactjs 和 Vuejs 建立 Component 的方式比對

April 20, 2017

最近這陣子剛好有機會接觸到 Vuejs,之前覺得會寫一點 Reactjs 應該就可以騙吃騙喝了(誤),但是這陣子感受到蠻多人好像都開始寫 Vuejs,不稍微碰一下感覺會落伍啊!其實學 Vuejs 是為了在 Laravel 前端上使用,之前稍微看過一些文章感覺真的蠻棒的!

以下的文章或許會有錯誤,I'm Vuejs rookie!希望在讀文章的各位不要鞭的太用力,若有錯誤歡迎指正!

Create Simple Todo List

How to create Reactjs Todo List Component:

const Todo = ({ todo }) => (
  <li>{todo.text}</li>
);

const TodoList = ({ todos }) => {
  const todoNode = todos.map(todo => <Todo todo={todo} key={todo.id} />);

  return (
    <ul>{todoNode}</ul>
  );
};

class App extends Component {
  constructor() {
    super();
    this.state = {
      todos: [
        { id: 1, text: 'Write Some Code' },
        { id: 2, text: 'Running' },
        { id: 3, text: 'Play Baskebtall' },
      ]
    };
  }

  render() {
    return (
      <div>
        <TodoList todos={this.state.todos} />
      </div>
    );
  }
}

How to create Vuejs Todo List Component:

<div id="app">
    <ul>
        <todo-item v-for="todo in todos" :key="todo.id" :todo="todo"></todo-item>
    </ul>
</div>
Vue.component('todo-item', {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`,
});

new Vue({
  el: '#app',
  data: {
    todos: [
      { id: 1, text: 'Write Some Code' },
      { id: 2, text: 'Running' },
      { id: 3, text: 'Play Baskebtall' },
    ]
  }
});

觀察 Reactjs 和 Vuejs 他們是如何傳遞 props

Reactjs 部分

Reactjs 主要透過自己特殊的 jsx 語法,看到 class App return 的地方:

<TodoList todos={this.state.todos} />
  1. 在 App constructor 初始化的 todos state
  2. <TodoList todos={this.state.todos} /> 的 tag todos,這是要傳到 child component 的 props name,可以透過這樣的方式不斷的往下傳遞 props,除了傳值之外也可以傳 function。
  3. const TodoList = ({ todos }) => { ... } 我們 destructuring 傳下來的 props,再把這些 todos 做 map 往 <Todo /> 傳下去。

Vuejs 部分

Vuejs 主要是從 HTML 上的 attribute 特性來實現的:

<todo-item v-for="todo in todos" :key="todo.id" :todo="todo"></todo-item>
  1. 看到 Vuejs 自己特殊的 v-for attribute,這裡就是 iterator todos 的 Object,也是我們熟悉的 for-in

  2. :key="todo.id"v-bind:key="todo.id" 的縮寫,後面的 :todo 也是。

  • 註:這裡的 :todo 是動態的,它會受到 parent component 影響,更多請參考官方文件說明
  1. todo-item 是由我們自己所定義的 Component,可以看到第二個參數物件內的 props
Vue.component('todo-item', {
  props: ['todo'],
  template: `<li>{{ todo.text }}</li>`,
});
  1. props: ['todo'] 是由 parent :todo 傳下來的 ,所以我們可以在 child component 內的 props 來接收。

我們在 root component 內已經先初始化 todos 的資料:

new Vue({
  el: '#app',
  data: {
    todos: [
      { id: 1, text: 'A' },
      { id: 2, text: 'B' },
      { id: 3, text: 'C' }
    ]
  }
});

加入新增 Todo 的方法

Reactjs 部分

// 新增一個 functional component

const InputTodo = ({ addTodo }) => {
  let inputText;

  return (
    <div>
      <input ref={input => inputText = input} />
      <button onClick={() => {
        addTodo(inputText.value);
        inputText.value = '';
      }}>Add</button>
    </div>
  );
};
// 在 App 新增一個 `addTodo` method

addTodo = (todo) => {
  const todoLength = this.state.todos.length;

  this.state.todos.push({
    id: todoLength + 1,
    text: todo,
  });

  this.setState({ todos: this.state.todos });
}

//

// 在 App return 內把 InputTodo Component 加入,
// 並把 `this.addTodo` function 作為 props 傳下去

<InputTodo addTodo={this.addTodo} />

Vuejs 部分

  1. 在 HTML 內加入一個 inputbutton
  2. input 使用 v-model 來 binding。
  3. button 監聽 onClick 事件,當被點擊時,觸發並使用 addTodo 這個 method 來處理。
<input v-model="text" />
<button @click="addTodo">Add</button>
  1. data 新增一個 text,主要是和 inputv-model="text" 做 binding,當 input 輸入值改變時,也會改變 data.text
  2. methods 是當一些 event 被觸發時,要對應到哪個 method 來做處理,這裡我們在 button 設定 @click="addTodo",所以在 methods 也要有對應的 addTodo method。
// 更新 JavaScript 部分

data: {
  text: '',
  todos: [
    { id: 1, text: 'Write Some Code' },
    { id: 2, text: 'Running' },
    { id: 3, text: 'Play Baskebtall' },
  ]
},
methods: {
  addTodo() {
    let todoLength = this.todos.length;

    this.todos.push({
      id: todoLength + 1,
      text: this.text,
    });

    this.text = '';
  }
},

大概可以稍微感受一下 Vuejs,不過看了一下官方文件,不過還蠻多很棒的特性都還沒有使用到啊!