前段时间实现了,组件之间的传值通过props层层传递太过繁琐,这次改进了项目引入了redux进行状态的管理。
1. 安装配置Redux
- 安装redux
yarn add redux复制代码
- 配置redux,在根目录下新建文件夹store,在store新建index.js,引入redux的createStore创建简单的store
import { createStore } from "redux";const reducer = function(state = [], action) { return state;}const store = createStore(reducer);复制代码
2. 组织Redux代码
- 新建store的目录结构如下所示
export const ADD_TODO = 'add_todo' // 增export const DELETE_TODO = 'delete_todo' // 删export const COMPLETE_TODO = 'complete_todo' // 改export const SEARCH_TODO = 'search_todo' // 查复制代码
- actions/index.js用来定义Action,Action 是把数据从应用传到 store 的有效载荷。它是 store 数据的唯一来源。一般来说你会通过 store.dispatch() 将 action 传到 store。这里使用Action创建函数来生成action
import {ADD_TODO, DELETE_TODO, COMPLETE_TODO, SEARCH_TODO} from '../constants'export function addTodo (todo) { return { type: ADD_TODO, todo }}export function deleteTodo (id) { return { type: DELETE_TODO, id }}export function completeTodo (id) { return { type: COMPLETE_TODO, id }}export function searchTodo (text) { return { type: SEARCH_TODO, text }}复制代码
- reducers/index.js定义reducer,reducer 就是一个纯函数,接收旧的 state 和 action,返回新的 state。指定了应用状态的变化如何响应 actions 并发送到 store 。
import {ADD_TODO, DELETE_TODO, COMPLETE_TODO, SEARCH_TODO} from '../constants'let initState = [ { id: 1, text: 'test123', completed: true }, { id: 2, text: 'testabc', completed: false }, { id: 3, text: 'done123', completed: true }]const todoReducer = (state = initState, action) => { switch (action.type) { case ADD_TODO: return [...state, action.todo] case DELETE_TODO: return state.filter(item => { return item.id !== action.id }) case COMPLETE_TODO: return state.map(item => { let obj = action.id === item.id ? {...item, completed: !item.completed} : item return obj }) case SEARCH_TODO: if (action.text === '') { return state } else { return state.filter(item => { return item.content.indexOf(action.text) !== -1 }) } default: return state }}export default todoReducer复制代码
- 最后修改store/index.js
import {createStore} from 'redux'import todoReducer from './reducers'const store = createStore(todoReducer)export default store复制代码
补充:如果有多个reducer,可以这样处理
import { combineReducers } from 'redux';import reducer1 from './reducers/reducer1'import reducer2 from './reducers/reducer2'const allReducers = { reducer1, reducer2}const rootReducer = combineReducers(allReducers);let store = createStore(rootReducer);复制代码
4. 安装调试工具
- 在Chrome中安装redux-devtools-extension插件
- 在终端安装redux-devtools-extension
yarn add redux-devtools-extension复制代码
- 安装完成后修改store/index.js
import {createStore} from 'redux'import todoReducer from './reducers'import {composeWithDevTools } from 'redux-devtools-extension'const store = createStore(todoReducer, composeWithDevTools())export default store复制代码
5. 测试redux
- 修改App.js,引入redux进行测试,store.subscribe注册事件监听当store.dispatch时可以通过store.getState()显示出当前的state
import React from 'react';import TodoList from './TodoList'import store from './store'import {addTodo} from './store/actions'store.subscribe(() => { console.log(store.getState())})store.dispatch(addTodo({id:4, text: 'nihao', completed: false}))function App() { return ();}export default App;复制代码
- 控制台打印结果如下,可以看到新添加的todo
- 在redux-devtools插件中也可以观察到状态变化
6. 集成react
- 安装react-redux
yarn add react-redux复制代码
- 修改app.js,使用Provider类将React应用程序包装在Redux容器中
import React, { Component } from 'react'import TodoListApp from './components/TodoListApp'import {Provider} from 'react-redux'import store from './store'class App extends Component { render () { return() }}export default App复制代码
7. 修改项目结构
- 容器组件和展示组件
- 容器组件负责与Store交互自身不会触发action,它向展示组件传递由Store获得的props,向Store派发用户操作展示组件引起的action。
- 展示组件专注于渲染视图是无状态组件,所有数据源于props,一般表示为函数式组件。
- 修改项目结构如下所示
- 修改todoItem
- components/TodoItem.js,此时的TodoItem只是负责展示作用没定义state,数据全部由props传入
import React from 'react';import { Typography, Button } from 'antd';import './TodoItem.less'const { Text } = Typography;function TodoItem ({completed, id, content, handleChangeItem,handleDeleteItem}) { return (handleChangeItem(id)} style={ {cursor: 'pointer'}}>)}export default TodoItem;复制代码{content}
- containers/TodoItems,向展示组件中传入数据
import {connect} from 'react-redux'import TodoItemComponent from '../components/TodoItem'import {completeTodo, deleteTodo} from '../store/actions'const mapDispatchToProps = dispatch => { return { handleChangeItem: id => { dispatch(completeTodo(id)) }, handleDeleteItem: id => { dispatch(deleteTodo(id)) } }}const TodoItemContainer = connect(null, mapDispatchToProps)(TodoItemComponent)export default TodoItemContainer复制代码
- 修改DataList
- 展示组件components/DataList
import React from 'react';import TodoItem from '../containers/TodoItem'import { List } from 'antd';function DataList ({list}) { return ((
)} /> )}export default DataList;复制代码
- 容器组件containers/Datalist
import {connect} from 'react-redux'import TodoListComponent from '../components/DataList'const mapStateToProps = state => { return { list: state }}const TodoListContainer = connect(mapStateToProps)(TodoListComponent)export default TodoListContainer复制代码
-
其他组件也按照上面展示组件和容器组件进行拆分详情查看
-
修改App.js,引入react-redux,被Provider包裹的组件都能拿到store
import React from 'react';import TodoListApp from './components/TodoListApp'import store from './store'import {Provider} from 'react-redux'function App() { return ();}export default App;复制代码
相关链接: