今天我會快速的過一下 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/...