日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

React狀態管理Redux的使用介紹詳解_React

作者:月光曬了很涼快 ? 更新時間: 2022-11-17 編程語言

1. 簡介

Redux 是 JavaScript 應用的狀態容器(對象),提供可預測的狀態管理。可以讓你開發出行為穩定可預測的應用,運行于不同的環境(客戶端、服務器、原生應用),并且易于測試。Redux 除了和 React 一起用外,還支持其它界面庫。

解決的問題:多層級組件間通信問題。

2. 核心概念

單一數據源

整個redux中的數據都是集中管理,存儲于同一個數據源中,數據源中的數據為單向數據流,不可直接修改。

純函數 (reducer) 統一對 state 數據修改

redux 定義了一個 reducer 函數來完成 state 數據的修改,reducer 會接收先前的 state 和 action,并返回新的 state。

  • 函數執行結果是可預期的(多次調用結果相同)
  • 函數執行不會觸發副作用
  • 函數中的變量,沒有使用外部的

3. redux工作流

①、store通過 reducer 創建了初始狀態

②、component 通過 store.getState() 獲取到了 store 中保存的 state 掛載在了自己的狀態上

③、用戶產生了操作,調用了 actions 的方法

④、actions 的方法被調用,創建了帶有標示性信息的 action(描述對象)

⑤、actions 將 action 通過調用 store.dispatch 方法發送到了 reducer 中

⑥、reducer 接收到 action 并根據標識信息判斷之后返回了新的 state

⑦、store 的 state 被 reducer 更改為新 state 的時候,store.subscribe 方法里的回調函數會執行,此時就可以通知 component 去重新獲取 state

4. 模擬redux工作流程

redux.js:

// 自定義的redux狀態管理
// 用 createStore 方法接收 reducer 純函數
export const createStore = reducer => {
    // 接收新的帶有單一數據源的對象
    let state = undefined
    // 訂閱隊列
    let tasks = []
    // 3.store.dispatch({type,payload})
    const dispath = action => {
        // 將 action 交給 reducer ,返回一個新的數據源
        state = reducer(state, action)
        // 數據源發生變化時,讓訂閱隊列中的每一個回調函數執行
        tasks.forEach(cb => cb())
    }
    const subscribe = cb => {
        // 把回調函數放入訂閱隊列中
        tasks.push(cb)
        // 取消訂閱時,刪除訂閱隊列中的回調函數
        return () => tasks.splice(tasks.indexOf(cb), 1)
    }
    // 返回數據源
    const getState = () => state
    // 2.初始化,防止組件第一次調用 getState 得到的是 undefined
    dispath({ type: '@@init@@' })
    // 返回 redux 工作流中需要的三個函數
    return {
        dispath,
        subscribe,
        getState
    }
}

index.js:

// 導入倉庫
import { createStore } from './redux'
// 5.設置一個初始值
const initState = {
    num: 100
}
// 4.創建 reducer 純函數
const reducer = (state = initState, action) => {
    // 完成組件中加的操作
    if (action.type === 'add') return { ...state, num: state.num + action.payload }
    return state;
}
const store = createStore(reducer)
export default store

App.jsx:

import React, { Component } from 'react'
// 組件中導入倉庫
import store from './store'
class App extends Component {
  componentDidMount() {
    // 訂閱 redux 的頻道,只要頻道發生更改,就會觸發視圖更新
    // 并且讓 unsubscribe 接收到 redux 中取消訂閱的函數
    this.unsubscribe = store.subscribe(() => this.forceUpdate())
  }
  componentWillUnmount() {
    // 取消訂閱,組件卸載時執行
    this.unsubscribe()
  }
  render() {
    return (
      <div>
        {/* 1.組件通過 getState 得到數據 */}
        <h3>{store.getState().num}</h3>
        <hr />
        <button
          onClick={() => {
            // 動作:添加;數據:每次加2
            store.dispath({ type: 'add', payload: 2 })
          }}
        >
          ++++
        </button>
      </div>
    )
  }
}
export default App

5. 使用redux

安裝 redux:

redux 沒有內嵌在 react 框架中,使用時需要手動去安裝:yarn add redux

安裝 redux-devtools:

安裝第3方模塊,讓調試工具顯示 state:

# yarn add -D @redux-devtools/extension
import { composeWithDevTools } from '@redux-devtools/extension'
const store = createStore(
  reducer,
  composeWithDevTools()
);

把上述案例,用真實的 redux 實現一下:

index.js:

// 1.導入redux中的createStore創建倉庫數據的方法
import { createStore } from 'redux'
// 配合瀏覽器安裝的插件來進行redux調試所用  
// 開發時有用,生產要關閉
import { composeWithDevTools } from '@redux-devtools/extension'
// 2.初始state數據
const initState = {
  num: 100
}
// 3.定義一個純函數reducer,專門用來操作state中的數據,要返回一個新的state
const reducer = (state = initState, action) => {
  if (action.type === 'add') return { ...state, num: state.num + action.payload }
  return state;
}
// 得到數據對象
let store
// 開發與生產環境的判斷,提高安全性
process.env.NODE_ENV === 'development'
  ?
  store = createStore(
    reducer,
    composeWithDevTools()
  )
  :
  store = createStore(
    reducer
  )
// 導出
export default store

6. react-redux

概述:

React-Redux 是 Redux 的官方針對 React 開發的擴展庫,默認沒有在 React 項目中安裝,需要手動來安裝。react-redux 是依賴于 redux,所以你必須安裝 redux。

你可以理解為 react-redux 就是 redux 給我們提供一些高階組件,能解決的問題是:使用它以后我們不需要在每個組件中再去手動訂閱數據的更新了,方便了 react 組件中調用 redux 中的數據。

安裝:

yarn add react-redux

使用步驟:

在程序主文件 index.js 文件中,定義 Provider。此處類似于之前跨組件通信處的 Provider 一樣,旨在讓全局的組件共享 store 中的數據。

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
// 導入Provider生產數據者組件
import { Provider } from 'react-redux'
// 導入數據源
import store from './store'
ReactDOM.render(
  // 包裹所有的路由
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root')
)

在組件中使用 react-redux

import React, { Component } from 'react'
// 提供一個高階組件 connect 用來把 redux 中的 state 和 action 映射到當前組件的 props 中
import { connect } from 'react-redux'
// 此函數必須要返回一個json對象
// 函數的 state 參數就是 redux 中的 state 數據
const mapStateToProps = state => {
  return { num: state.num }
}
// mapStateToProps 函數的兩種簡寫寫法
// const mapStateToProps = state => state
// @connect(state => state, mapDispatchToProps)
// 此函數必須要返回一個json對象
// dispatch 就是之前通過 store.dispatch 的方法
const mapDispatchToProps = dispatch => {
  return {
    add(n = 1) {
      // 動作:增加,數據:n
      dispatch({ type: 'add', payload: n })
    }
  }
}
// 函數的方式可以同步也可以異步,dispatch 是你手動在需要的地方來調用
// const mapDispatchToProps = dispatch => {
//   return {
//     add(n = 1) {
//       setTimeout(() => {
//         dispatch({ type: 'add', payload: n })
//       }, 1000)
//     }
//   }
// }
// 該函數的對象寫法:
// 如果為對象方式則只能使用同步,不能用異步,因為在 connect 實現時如果是對象,則它會主動調用 dispatch
// 調用了 dispatch 它就立刻執行。而如果是一個異步,則就會不符合 dispatch 要求,則報錯
// const mapDispatchToProps = {
//   add: (n = 1) => ({ type: 'add', payload: n })
// }
// 參數1:函數,把 redux 中的 state 數據映射到當前的 props 屬性中
// 參數2:函數|對象,把你操作的 dispatch 方法映射到當前的 props 屬性中
@connect(mapStateToProps, mapDispatchToProps)
class App extends Component {
  render() {
    console.log('props', this.props)
    return (
      <div>
        <h3>{this.props.num}</h3>
        <hr />
        <button onClick={() => this.props.add()}>++++</button>
      </div>
    )
  }
}
export default App

上面是使用裝飾器的寫法,還有不使用裝飾器的寫法:

我們需要將裝飾器一行注釋,并且修改導出方式。

原文鏈接:https://blog.csdn.net/weixin_45605541/article/details/127061122

欄目分類
最近更新