React 快速上手 - 08 redux 狀態管理 react-redux

redux

目錄

React 快速上手 - 08 redux 狀態管理 react-redux

今天我會快速的過一下 redux 知識,而後討論下 適用性,最後爲了讓你們能快速學習,簡化了官方的經典 Demo todo ,跟着我作一遍就行。前端

目標

  • 告終什麼是 redux
  • 什麼狀況下適用
  • 建立一個 redux 應用
  • 安裝調試插件

閒話

redux 是一個很深的話題,先聊聊標準學習路線,打開 https://redux.js.org/introductionnode

筆者爲了寫這文章,但是安靜的讀了一遍react

首先 Introduction 7 篇git

redux-introduction

好像懂了什麼,不知道呢github

而後 Base 6 篇web

redux-Base

其實 Example: Todo List 這纔是最有幫助的chrome

又聽了視頻 Getting Started with Redux 視頻redux

好囉嗦啊segmentfault

Redux 視頻 Getting Started with Redux

不過這也是學習的正確姿式,總要看一遍官方文檔,無奈官網設計的更像一個學術站點,而不是類庫工具一類的指導說明api

好了好了~吐槽完畢,開始正文!

redux 是什麼, 能夠不用麼

ducafecat_2018-05-25-11-27-37

這張圖是 Flux 官網的,畫的很好。

Redux 是一種 數據的管理 方式,界面上發起各類操做 Action ,而後 DispatcherStore 更新狀態 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 在彈幕業務中就兩步:

    1. 彈幕發出組件 執行發出彈幕動做 Action 內容 { type: 'BARRAGE_SEND', text: '彈幕消息' }
    2. 彈幕滾動組件 新彈幕數據被更新到彈幕滾動組件

可是也很差濫用,我看到有些簡單的 表單操做,居然也套了 Redux ,徹底不必,本身把握吧

動手建立一個 redux 應用

來個經典例子 todo , 原版 Todo , 我這裏是精簡版,那麼咱們開始

  • 動圖效果

react-redux-todo

  • 組件結構

todo 組件結構

第一步: 編寫 Action

界面上產生的操做

let nextTodoId = 0

export const addTodo = text => ({
  type: 'ADD_TODO',
  id: nextTodoId++,
  text
})

export const toggleTodo = id => ({
  type: 'TOGGLE_TODO',
  id
})
  • 事件的格式

    • type 字段必須有,表示作什麼操做
    • type 值全局惟一
    • type 大寫定義
    • 其它字段自由定義

第二步: 編寫 Reducers

事件對應的響應處理,處理完後返回新 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

第三步: 合併 Reducers

使用 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)) 就發動了 ReduxReducers , 這時 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
  • 標準代碼格式

    1. createStore(reducers) 建立 store
    2. Provider 適配器壓入 store 對象, 子節點都受 Redux 控制

調試工具 Redux DevTools extension

動圖效果

Redux DevTools extension

1. 安裝 chrome 插件

打開 redux-devtools

redux-devtools

2. 配置代碼

const store = createStore(
  todoReducer,
  window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
)

createStore 時加入 window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()

3. 開啓插件

打開 chrome 調試工具,點擊面板 Redux

chrome-tab-Redux

codepen

https://codepen.io/ducafecat/...

代碼

參考

相關文章
相關標籤/搜索