iT邦幫忙

2019 iT 邦幫忙鐵人賽

DAY 15
0
自我挑戰組

請你當我的好朋友吧!ReactJS!系列 第 15

【DAY 15】利用redux與react搭配在做出一個To do list吧!(上)

【前言】
  呼~~終於進行到一半了(灑花!越來越不知道前言要寫什麼來湊字數了XD
【正文】
  在這次的範例,我們要利用redux與react再次做一個to do list(其實是我懶得再想範例)。由於redux其實是可以獨立使用,也就是react本身是沒有redux這個套件,所以我們一開始要在我們的專案底下輸入npm install --save react-redux安裝redux哦。
  再來是redux中的react還有兩個名詞:Presentational ComponentContainer Component,這兩個又是什麼阿?下面來自redux官網的表格可以解釋這兩個的差別:
  presentional vs Container
  基本上Presental Component主要是UI的顯示,而Container Component主要的功能就是與redux中的store做連結的。因此,根據上表的對於兩個的特性,我們可以對這個to do list大致分為:

  • Presentational Component
     1. TodoList:顯示to do list
     2. Todo:to do項目
     3. Link:filter連結
     4. Footer:顯示Link的區塊
     5. App:根組件
  • Container Component
     1. VisibleTodoList:根據目前的Filter去render對應的TodoList
     2. FilterLink:拿到目前的Filter去render Link
  • Other Component
     1. AddTodo:有add功能的輸入按鈕組件

  也就是說,TodoList組件的內容會透過VisibleTodoList對於redux中的store監聽的state,將最新的state狀態回傳,LinkFilterLink亦然。

  • TodoList.js
import React from 'react';
// prop-type:變數型別定義
import PropTypes from 'prop-types';
import Todo from './Todo';

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {/* 根據todos去map出來Todo Component */}
    {todos.map((todo, index) => (
      <Todo key={index} {...todo} onClick={() => onTodoClick(index)} />
    ))}
  </ul>
);

TodoList.propTypes = {
  // todos是個array,裡面存的是帶數字的id屬性、布林的completed屬性、字串的text屬性的物件
  todos: PropTypes.arrayOf(
    PropTypes.shape({
      id: PropTypes.number.isRequired,
      completed: PropTypes.bool.isRequired,
      text: PropTypes.string.isRequired,
    }).isRequired,
  ).isRequired,
  // onTodoClick是個函式
  onTodoClick: PropTypes.func.isRequired,
};

export default TodoList;

Todos和onTodoClick都是由VisibleTodoList傳遞來的

  • Todo.js
import React from 'react';
import PropTypes from 'prop-types';
const Todo = ({ onClick, completed, text }) => (
  <li
    onClick={onClick}
    // Todo Item的style
    style={ {
      textDecoration: completed ? 'line-through' : 'none'
    }}
  >
    {text}
  </li>
);

Todo.propTypes = {
  onClick: PropTypes.func.isRequired,
  completed: PropTypes.bool.isRequired,
  text: PropTypes.string.isRequired,
};

export default Todo;
  • Link.js
import React from 'react';
import PropTypes from 'prop-types';

class Link extends React.Component {

  onclick = (e) => {
    e.preventDefault();
    const { onClick } = this.props;
    onClick();
  }

  render() {
    const { active, children } = this.props;
    if (active) {
      return <span>{children}</span>
    }

    return (
      <a href="#" onClick={this.onclick}>
        {children}
      </a>
    )
  }
}
Link.propTypes = {
  active: PropTypes.bool.isRequired,
  children: PropTypes.node.isRequired,
  onClick: PropTypes.func.isRequired,
};

export default Link;

onClick、active是由FilterLink傳遞來的

  • Footer.js
import React from 'react';
import FilterLink from '../containers/FilterLink';
import { VisibilityFilters } from '../../actions';

const Footer = () => (
  <div>
    Show:
    {' '}
    <FilterLink filter={VisibilityFilters.SHOW_ALL}>
      All
    </FilterLink>
    {', '}
    <FilterLink filter={VisibilityFilters.SHOW_ACTIVE}>
      Active
    </FilterLink>
    {', '}
    <FilterLink filter={VisibilityFilters.SHOW_COMPLETED}>
      Completed
    </FilterLink>
  </div>
);

export default Footer;
  • App.js
import React from 'react';
import Footer from './Footer';
import AddTodo from '../containers/AddTodo';
import VisibleTodoList from '../containers/VisibleTodoList';

const App = () => (
  <div>
    <AddTodo />
    <VisibleTodoList />
    <Footer />
  </div>
)

export default App;

  今天我們先把Presentational Component的部分先寫完,明天來寫Container Component吧!


上一篇
【DAY 14】狀態儲存在redux的Store中吧!
下一篇
【DAY 16】利用redux與react搭配在做出一個to do list吧!(中)
系列文
請你當我的好朋友吧!ReactJS!30

尚未有邦友留言

立即登入留言