今天我会快速的过一下 redux
知识,而后讨论下 适用性
,最后为了让你们能快速学习,简化了官方的经典 Demo todo
,跟着我作一遍就行。前端
redux
是一个很深的话题,先聊聊标准学习路线,打开 https://redux.js.org/introductionnode
笔者为了写这文章,但是安静的读了一遍react
首先 Introduction
7 篇git
好像懂了什么,不知道呢github
而后 Base
6 篇web
其实 Example: Todo List 这才是最有帮助的chrome
又听了视频 Getting Started with Redux 视频redux
好啰嗦啊segmentfault
不过这也是学习的正确姿式,总要看一遍官方文档,无奈官网设计的更像一个学术站点,而不是类库工具一类的指导说明api
好了好了~吐槽完毕,开始正文!
这张图是 Flux 官网的,画的很好。
Redux
是一种 数据的管理
方式,界面上发起各类操做 Action
,而后 Dispatcher
到 Store
更新状态 State
,推送新状态到视图 View
好了,概念一句话说完了,来看看什么状况下用 Redux
这个界面,若是用 React
来实现,在底部的 容器组件
要处理的业务有: 用户登陆、弹幕、主播信息、视频进度、道具、打赏、IM聊天、等等还有不少 并且随着产品迭代,功能只会多
按咱们以前的组件拆分,结构是合理,可是这个数据管理麻烦了,各类业务数据压入子组件,各类业务事件返回到主容器组件,可能的代码结构以下
// 状态 this.state = { data1:..., data2:..., data3:..., data...n:... } // 事件 function handelEvent1 = {...} function handelEvent2 = {...} function handelEvent3 = {...} function handelEvent...n = {...} // JSX <主视图组件> <用户信息 data1={this.state.data1} handleEven1={...} handleEven2={...} handleEven...n={...} /> <主播信息> <基础资料 data...n={...} handleEven...n={...} /> <头像 data...n={...} handleEven...n={... /> <关注 data...n={...} handleEven...n={... /> <标签 data...n={...} handleEven...n={... /> <热度 data...n={...} handleEven...n={... /> ... </主播信息> <播放器 ...> <... /> ... <播放器> ... <...播放器/> ... </主视图组件>
会发现组件套组件,父父子子的,彻底无法维护了,梳理这些关系就很费时间,并且容易错误
Redux
就是来解决这个问题的,每一个组件只要执行本身的 Action
,不用返回到父容器
好比 Redux
在弹幕业务中就两步:
弹幕发出组件
执行发出弹幕动做 Action
内容 { type: 'BARRAGE_SEND', text: '弹幕消息' }
弹幕滚动组件
新弹幕数据被更新到弹幕滚动组件可是也很差滥用,我看到有些简单的 表单操做,居然也套了 Redux
,彻底不必,本身把握吧
来个经典例子 todo
, 原版 Todo , 我这里是精简版,那么咱们开始
界面上产生的操做
let nextTodoId = 0 export const addTodo = text => ({ type: 'ADD_TODO', id: nextTodoId++, text }) export const toggleTodo = id => ({ type: 'TOGGLE_TODO', id })
事件的格式
type
字段必须有,表示作什么操做type
值全局惟一type
大写定义事件对应的响应处理,处理完后返回新 state
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
使用 combineReducers
合并全部的处理过程
import { combineReducers } from 'redux' import todos from './todos' export default combineReducers({ todos })
假设你有其它业务, 如: 用户 user
, 购物车 cart
import { combineReducers } from 'redux' import todos from './todos' import user from './user' import cart from './cart' export default combineReducers({ todos, user, cart })
AddTodo
connect
链接组件dispatch
方法派发事件import React from 'react' import { connect } from 'react-redux' import { addTodo } from '../redux/actions' const AddTodo = ({ dispatch }) => { let input return ( <div> <form onSubmit={e => { e.preventDefault() if (!input.value.trim()) { return } dispatch(addTodo(input.value)) input.value = '' }}> <input ref={node => input = node} /> <button type="submit"> Add Todo </button> </form> </div> ) } export default connect()(AddTodo)
dispatch(addTodo(input.value))
就发动了 Redux
到 Reducers
, 这时 state
更新了
TodoList
再来个稍微复杂的
import React from 'react' import {connect} from 'react-redux' import {toggleTodo} from '../redux/actions' const Todo = ({onClick, completed, text}) => ( <li onClick={onClick} style={{ textDecoration: completed ? 'line-through' : 'none' }} > {text} </li> ) const TodoList = ({todos, toggleTodo}) => ( <ul> {todos.map(todo => ( <Todo key={todo.id} {...todo} onClick={() => toggleTodo(todo.id)} /> ))} </ul> ) const mapStateToProps = state => ({ todos: state.todos }) const mapDispatchToProps = dispatch => ({ toggleTodo: id => dispatch(toggleTodo(id)) }) export default connect(mapStateToProps, mapDispatchToProps)(TodoList)
仍是 connect
方法 , 这里重点讲下
先看看官方定义 connect()
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
名称 | 说明 |
---|---|
mapStateToProps | store 绑定 state , 作更新的须要传入 |
mapDispatchToProps | 绑定派发事件 event , 不传的话默认 dispatch 对象, 就像上面的 AddTodo 组件 |
mergeProps | [mergeProps(stateProps, dispatchProps, ownProps): props] (Function): 合并属性自定义,本身不传的话默认 ·Object.assign ,我也是放空默认的 |
options | 一些选项,我没怎么在乎,知道有就行 |
[mapStateToProps], [mapDispatchToProps]
这两个用到的多,你们本身练习下
import React from 'react' import AddTodo from './AddTodo' import TodoList from './TodoList' const App = () => ( <div> <AddTodo /> <TodoList /> </div> ) export default App
这里简单,并列排放
App
import React, {Component} from 'react' import {createStore} from 'redux' import {Provider} from 'react-redux' import TodoApp from './todos/components/App' import todoReducer from './todos/redux/reducers' const store = createStore(todoReducer) class BaseRedux extends Component { render() { return ( <Provider store={store}> <TodoApp /> </Provider> ) } } export default BaseRedux
标准代码格式
createStore(reducers)
建立 store
Provider
适配器压入 store
对象, 子节点都受 Redux
控制Redux DevTools extension
动图效果
const store = createStore( todoReducer, window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__() )
createStore
时加入 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
打开 chrome
调试工具,点击面板 Redux
https://codepen.io/ducafecat/...