Redux 例子分析: todos

代码来源:https://github.com/reactjs/redux/tree/master/examples/todos
source 目录夹结构(不包含测试,即spec.js结尾文件):

- actions
    - index.js
- components
    - App.js
    - Footer.js
    - Link.js
    - Todo.js
    - TodoList.js
- containers
    - AddTodo.js
    - FilterLink.js
    - VisibleTodoList.js
- reducers
    - index.js
    - todos.js
    - visibilityFilter.js
- index.js

文件之间的逻辑层次关系:

  • index.js
    • ./reducers/index.js
      • ./reducers/todos.js
      • ./reducers/visibilityFilter.js
    • ./components/App.js
      • ./containers/AddTodo.js
        • ./actions/index.js - addTodo
      • ./containers/VisibleTodoList.js
        • ./actions/index.js - toggleTodo
        • ./components/TodoList.js
      • ./components/Footer.js
        • ./containers/FilterLink.js
          • ./actions/index.js - setVisibilityFilter
          • ./components/Link.js

以下是细节分析,从index.js展开,然后逐层展开:

// index.js
import React from 'react'
import { render } from 'react-dom'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import App from './components/App'
import reducer from './reducers'

const store = createStore(reducer)

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

既然是redux,那么要把所有的数据都存在store里面:
const store = createStore(reducer)
和 counter 的例子不同,这里用到了 Provider,他带了一个 store property,在它里面的 component 都可以访问它的store里面的内容。

<Provider store={store}>
  <App />
</Provider>

仅仅看到这里,感觉有点抽象,那么<App />是什么呢?

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

还是有点抽象,以<VisibleTodoList />展开来看:

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'SHOW_ALL':
      return todos
    case 'SHOW_COMPLETED':
      return todos.filter(t => t.completed)
    case 'SHOW_ACTIVE':
      return todos.filter(t => !t.completed)
    default:
      throw new Error('Unknown filter: ' + filter)
  }
}

const mapStateToProps = (state) => ({
  todos: getVisibleTodos(state.todos, state.visibilityFilter)
})

const mapDispatchToProps = {
  onTodoClick: toggleTodo
}

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

export default VisibleTodoList

收缩函数体:

import { connect } from 'react-redux'
import { toggleTodo } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {}
const mapStateToProps = (state) => ({
  todos: getVisibleTodos(state.todos, state.visibilityFilter)
})
const mapDispatchToProps = {
  onTodoClick: toggleTodo
}
const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)
export default VisibleTodoList

看到重点了没有,关键在于:

const VisibleTodoList = connect(
  mapStateToProps,
  mapDispatchToProps
)(TodoList)

connect将特定格式的函数mapStateToPropsmapDispatchToPropsTodoList联系在一起。
展开TodoListtoggleTodo可见:

const TodoList = ({ todos, onTodoClick }) => (
  <ul>
    {todos.map(todo =>
      <Todo
        key={todo.id}
        {...todo}
        onClick={() => onTodoClick(todo.id)}
      />
    )}
  </ul>
)

TodoList.propTypes = {
  todos: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.number.isRequired,
    completed: PropTypes.bool.isRequired,
    text: PropTypes.string.isRequired
  }).isRequired).isRequired,
  onTodoClick: PropTypes.func.isRequired
}
export const toggleTodo = (id) => ({
  type: 'TOGGLE_TODO',
  id
})

从中,可以看到mapStateToPropsmapDispatchToProps和他们对应关系。
mapStateToProps访问了TodoList.propTypes中的todosmapDispatchToProps访问了TodoList.propTypes中的onTodoClick,并且会间接调用reducer,在这里 toggleTodo对应的是todo.js中的:

    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id) 
          ? {...todo, completed: !todo.completed}
          : todo
      )

读者可以自己研究<AddTodo /><Footer />

可以直接到官方的演示地址查看代码和显示效果:codesandbox todos

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值