让前端飞Web前端之路React.js

我理解的todos(redux+react-redux)

2019-01-17  本文已影响5人  换昵称了

demo地址:

git clone https://github.com/reactjs/redux.git
cd redux/examples/todos
npm install
npm start

3.第一部分(如图)

addTodo.png
1.入口文件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 rootReducer from './reducers'

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

Provider作用:将store传给组件,与connect配合使用,connect则是将组件与redux关联起来。本质上 Provider 就是给 connect 提供 store 用的。(react-redux提供)

2.组件入口App.js
import React from 'react';
import AddTodo from '../containers/AddTodo'
import VisibleTodoList from '../containers/VisibleTodoList'
// 使用jsx写法一定要引入react,不然会报错:'React' must be in scope when using JSX  react/react-in-jsx-scope
const App = () => {
    return (
        <div>
            <AddTodo />
            <VisibleTodoList />
        </div>
    )
}

export default App;
3.AddTodo 的action以及reducer
//action.js   
let nextTodoId = 0;
export const addTodo = (text) => {
    return {
        type: 'ADD_TODO',
        //id存在的意义是作为key
        id: nextTodoId++,
        text
    }
}
//reducer
const todos = (state = [], action) => {
    switch (action.type) {
        case 'ADD_TODO':
            return [
                ...state,
                {
                    id: action.id,
                    text: action.text,
                    completed: false
                }
            ]
        default:
            return state
    }
}

export default todos

上面我们已经将reducer作为参数传入了store,所以只要触发dipatch,就会根据type做出相应的更新。
...state解构写法,一定要给state一个默认值,不然会报错。

4.组件AddTodo.js
import React from 'react'
import { addTodo } from '../actions'
import { connect } from 'react-redux'
//{dispatch}解构写法,也可以写成任意一个变量名,比如a,获取dipatch:a.dipatch
const AddTodo = ({ dispatch }) => {
    let input;
    return (
        <form action="" onSubmit={
            (e) => {
                e.preventDefault() //阻止默认事件,比如这里点击按钮会刷新页面
                dispatch(addTodo(input.value))
                input.value = ''
            }
        }>
            <input type="text" ref={node => { input = node }} />
            <button type="submit">
                addTodo
            </button>
        </form>
    )
}

export default connect()(AddTodo)

action和reducer之间能联系起来的关键是connect,connect将store和组件联系起来,即connect连接视图和数据层。通过provider把store绑定在组件上(provider为connect提供了store),当dispatch 的时候,会更新相对应type的store数据 。(有点乱,对于connect的具体解析可参考https://www.jianshu.com/p/9873d4ccb891(关于react-redux中的connect用法介绍及原理解析))

5.VisibleTodoList.js
import { connect } from 'react-redux'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos) => {
    console.log(todos)
    return todos
}
const mapStateToProps = state => ({
    todos: getVisibleTodos(state.todos)
})

export default connect(
    mapStateToProps
)(TodoList)

connect的个人总结:

第二部分(如图)

todoList.png
1.actions 和reducers
//actions
export const VisibilityFilters = {
    SHOW_ALL: 'SHOW_ALL',
    SHOW_COMPLETED: 'SHOW_COMLETED',
    SHOW_ACTIVE: 'SHOW_ACTIVE'
}

export const toggleTodo = (id) => (
    {
        type: 'TOGGLE_TODO',
        id
    }
)

VisibilityFilters是用来判断三种列表显示状态。SHOW_ALL显示全部,SHOW_COMPLETED显示已完成的,SHOW_ACTIVE显示正在进行的

//reducers
const todos = (state = [], action) => {
  switch (action.type) {
    case 'ADD_TODO':
      return [
        ...state,
        {
          id: action.id,
          text: action.text,
          completed: false
        }
      ]
    case 'TOGGLE_TODO':
      return state.map(todo =>
        (todo.id === action.id)
          ? {...todo, completed: !todo.completed}
          : todo
      )
    default:
      return state
  }
}

export default todos
2.组件

TodoList.js

import React from 'react'
import Todo from './Todo'

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

export default TodoList

Todo.js

import React from 'react'
const Todo = ({ onClick, completed, text }) => (
    <li
        onClick={onClick}
        style={{
            textDecoration: completed ? 'line-through' : 'none'
        }}
    >
        {text}
    </li>
)

export default Todo
这部分的重点
import { connect } from 'react-redux'
import { toggleTodo, VisibilityFilters } from '../actions'
import TodoList from '../components/TodoList'

const getVisibleTodos = (todos, filter) => {
    switch (filter) {
        case VisibilityFilters.SHOW_ALL:
            return todos
        case VisibilityFilters.SHOW_COMPLETED:
            return todos.filter(t => t.completed)
        case VisibilityFilters.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 = dispatch => ({
    toggleTodo: id => dispatch(toggleTodo(id))
})

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(TodoList)

我的理解:
通过connect把组件与store建立起联系。
传入的第一个参数mapStateToProps,我们将store中的数据作为props绑定到组件中,所以这里我们能拿得到state。
传入的第二个参数mapDispatchToProps,参数是dispatch,则是我们将action作为props绑定到组件中,所以当我们点击todoList 的时候,就会触发dispatch,返回包含对应action的object对象。
回到todoList:todoList的两个参数{todos,toggleTodo}就是这样获取的。通过解构在Todo中拿到了action对应的两个参数{completed,text}

上一篇下一篇

猜你喜欢

热点阅读