React狀態(tài)管理Redux的使用介紹詳解
1. 簡(jiǎn)介
Redux 是 JavaScript 應(yīng)用的狀態(tài)容器(對(duì)象),提供可預(yù)測(cè)的狀態(tài)管理??梢宰屇汩_發(fā)出行為穩(wěn)定可預(yù)測(cè)的應(yīng)用,運(yùn)行于不同的環(huán)境(客戶端、服務(wù)器、原生應(yīng)用),并且易于測(cè)試。Redux 除了和 React 一起用外,還支持其它界面庫。
解決的問題:多層級(jí)組件間通信問題。
2. 核心概念
單一數(shù)據(jù)源
整個(gè)redux中的數(shù)據(jù)都是集中管理,存儲(chǔ)于同一個(gè)數(shù)據(jù)源中,數(shù)據(jù)源中的數(shù)據(jù)為單向數(shù)據(jù)流,不可直接修改。
純函數(shù) (reducer) 統(tǒng)一對(duì) state 數(shù)據(jù)修改
redux 定義了一個(gè) reducer 函數(shù)來完成 state 數(shù)據(jù)的修改,reducer 會(huì)接收先前的 state 和 action,并返回新的 state。
- 函數(shù)執(zhí)行結(jié)果是可預(yù)期的(多次調(diào)用結(jié)果相同)
- 函數(shù)執(zhí)行不會(huì)觸發(fā)副作用
- 函數(shù)中的變量,沒有使用外部的
3. redux工作流
①、store通過 reducer 創(chuàng)建了初始狀態(tài)
②、component 通過 store.getState() 獲取到了 store 中保存的 state 掛載在了自己的狀態(tài)上
③、用戶產(chǎn)生了操作,調(diào)用了 actions 的方法
④、actions 的方法被調(diào)用,創(chuàng)建了帶有標(biāo)示性信息的 action(描述對(duì)象)
⑤、actions 將 action 通過調(diào)用 store.dispatch 方法發(fā)送到了 reducer 中
⑥、reducer 接收到 action 并根據(jù)標(biāo)識(shí)信息判斷之后返回了新的 state
⑦、store 的 state 被 reducer 更改為新 state 的時(shí)候,store.subscribe 方法里的回調(diào)函數(shù)會(huì)執(zhí)行,此時(shí)就可以通知 component 去重新獲取 state
4. 模擬redux工作流程
redux.js:
// 自定義的redux狀態(tài)管理 // 用 createStore 方法接收 reducer 純函數(shù) export const createStore = reducer => { // 接收新的帶有單一數(shù)據(jù)源的對(duì)象 let state = undefined // 訂閱隊(duì)列 let tasks = [] // 3.store.dispatch({type,payload}) const dispath = action => { // 將 action 交給 reducer ,返回一個(gè)新的數(shù)據(jù)源 state = reducer(state, action) // 數(shù)據(jù)源發(fā)生變化時(shí),讓訂閱隊(duì)列中的每一個(gè)回調(diào)函數(shù)執(zhí)行 tasks.forEach(cb => cb()) } const subscribe = cb => { // 把回調(diào)函數(shù)放入訂閱隊(duì)列中 tasks.push(cb) // 取消訂閱時(shí),刪除訂閱隊(duì)列中的回調(diào)函數(shù) return () => tasks.splice(tasks.indexOf(cb), 1) } // 返回?cái)?shù)據(jù)源 const getState = () => state // 2.初始化,防止組件第一次調(diào)用 getState 得到的是 undefined dispath({ type: '@@init@@' }) // 返回 redux 工作流中需要的三個(gè)函數(shù) return { dispath, subscribe, getState } }
index.js:
// 導(dǎo)入倉庫 import { createStore } from './redux' // 5.設(shè)置一個(gè)初始值 const initState = { num: 100 } // 4.創(chuàng)建 reducer 純函數(shù) 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' // 組件中導(dǎo)入倉庫 import store from './store' class App extends Component { componentDidMount() { // 訂閱 redux 的頻道,只要頻道發(fā)生更改,就會(huì)觸發(fā)視圖更新 // 并且讓 unsubscribe 接收到 redux 中取消訂閱的函數(shù) this.unsubscribe = store.subscribe(() => this.forceUpdate()) } componentWillUnmount() { // 取消訂閱,組件卸載時(shí)執(zhí)行 this.unsubscribe() } render() { return ( <div> {/* 1.組件通過 getState 得到數(shù)據(jù) */} <h3>{store.getState().num}</h3> <hr /> <button onClick={() => { // 動(dòng)作:添加;數(shù)據(jù):每次加2 store.dispath({ type: 'add', payload: 2 }) }} > ++++ </button> </div> ) } } export default App
5. 使用redux
安裝 redux:
redux 沒有內(nèi)嵌在 react 框架中,使用時(shí)需要手動(dòng)去安裝:yarn add redux
安裝 redux-devtools:
安裝第3方模塊,讓調(diào)試工具顯示 state:
# yarn add -D @redux-devtools/extension import { composeWithDevTools } from '@redux-devtools/extension' const store = createStore( reducer, composeWithDevTools() );
把上述案例,用真實(shí)的 redux 實(shí)現(xiàn)一下:
index.js:
// 1.導(dǎo)入redux中的createStore創(chuàng)建倉庫數(shù)據(jù)的方法 import { createStore } from 'redux' // 配合瀏覽器安裝的插件來進(jìn)行redux調(diào)試所用 // 開發(fā)時(shí)有用,生產(chǎn)要關(guān)閉 import { composeWithDevTools } from '@redux-devtools/extension' // 2.初始state數(shù)據(jù) const initState = { num: 100 } // 3.定義一個(gè)純函數(shù)reducer,專門用來操作state中的數(shù)據(jù),要返回一個(gè)新的state const reducer = (state = initState, action) => { if (action.type === 'add') return { ...state, num: state.num + action.payload } return state; } // 得到數(shù)據(jù)對(duì)象 let store // 開發(fā)與生產(chǎn)環(huán)境的判斷,提高安全性 process.env.NODE_ENV === 'development' ? store = createStore( reducer, composeWithDevTools() ) : store = createStore( reducer ) // 導(dǎo)出 export default store
6. react-redux
概述:
React-Redux 是 Redux 的官方針對(duì) React 開發(fā)的擴(kuò)展庫,默認(rèn)沒有在 React 項(xiàng)目中安裝,需要手動(dòng)來安裝。react-redux 是依賴于 redux,所以你必須安裝 redux。
你可以理解為 react-redux 就是 redux 給我們提供一些高階組件,能解決的問題是:使用它以后我們不需要在每個(gè)組件中再去手動(dòng)訂閱數(shù)據(jù)的更新了,方便了 react 組件中調(diào)用 redux 中的數(shù)據(jù)。
安裝:
yarn add react-redux
使用步驟:
在程序主文件 index.js 文件中,定義 Provider。此處類似于之前跨組件通信處的 Provider 一樣,旨在讓全局的組件共享 store 中的數(shù)據(jù)。
import React from 'react' import ReactDOM from 'react-dom' import App from './App' // 導(dǎo)入Provider生產(chǎn)數(shù)據(jù)者組件 import { Provider } from 'react-redux' // 導(dǎo)入數(shù)據(jù)源 import store from './store' ReactDOM.render( // 包裹所有的路由 <Provider store={store}> <App /> </Provider>, document.getElementById('root') )
在組件中使用 react-redux
import React, { Component } from 'react' // 提供一個(gè)高階組件 connect 用來把 redux 中的 state 和 action 映射到當(dāng)前組件的 props 中 import { connect } from 'react-redux' // 此函數(shù)必須要返回一個(gè)json對(duì)象 // 函數(shù)的 state 參數(shù)就是 redux 中的 state 數(shù)據(jù) const mapStateToProps = state => { return { num: state.num } } // mapStateToProps 函數(shù)的兩種簡(jiǎn)寫寫法 // const mapStateToProps = state => state // @connect(state => state, mapDispatchToProps) // 此函數(shù)必須要返回一個(gè)json對(duì)象 // dispatch 就是之前通過 store.dispatch 的方法 const mapDispatchToProps = dispatch => { return { add(n = 1) { // 動(dòng)作:增加,數(shù)據(jù):n dispatch({ type: 'add', payload: n }) } } } // 函數(shù)的方式可以同步也可以異步,dispatch 是你手動(dòng)在需要的地方來調(diào)用 // const mapDispatchToProps = dispatch => { // return { // add(n = 1) { // setTimeout(() => { // dispatch({ type: 'add', payload: n }) // }, 1000) // } // } // } // 該函數(shù)的對(duì)象寫法: // 如果為對(duì)象方式則只能使用同步,不能用異步,因?yàn)樵?connect 實(shí)現(xiàn)時(shí)如果是對(duì)象,則它會(huì)主動(dòng)調(diào)用 dispatch // 調(diào)用了 dispatch 它就立刻執(zhí)行。而如果是一個(gè)異步,則就會(huì)不符合 dispatch 要求,則報(bào)錯(cuò) // const mapDispatchToProps = { // add: (n = 1) => ({ type: 'add', payload: n }) // } // 參數(shù)1:函數(shù),把 redux 中的 state 數(shù)據(jù)映射到當(dāng)前的 props 屬性中 // 參數(shù)2:函數(shù)|對(duì)象,把你操作的 dispatch 方法映射到當(dāng)前的 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
上面是使用裝飾器的寫法,還有不使用裝飾器的寫法:
我們需要將裝飾器一行注釋,并且修改導(dǎo)出方式。
到此這篇關(guān)于React狀態(tài)管理Redux的使用介紹詳解的文章就介紹到這了,更多相關(guān)React Redux內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
react自定義實(shí)現(xiàn)狀態(tài)管理詳解
這篇文章主要為大家詳細(xì)介紹了react如何自定義實(shí)現(xiàn)狀態(tài)管理,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01react 項(xiàng)目 中使用 Dllplugin 打包優(yōu)化技巧
在用 Webpack 打包的時(shí)候,對(duì)于一些不經(jīng)常更新的第三方庫,比如 react,lodash,vue 我們希望能和自己的代碼分離開,這篇文章主要介紹了react 項(xiàng)目 中 使用 Dllplugin 打包優(yōu)化,需要的朋友可以參考下2023-01-01React + Node.js實(shí)現(xiàn)圖片上傳功能
最近筆者在開發(fā)個(gè)人博客的后臺(tái)管理系統(tǒng),里面用到了圖片上傳相關(guān)的功能,在這里記錄并分享一下,希望可以幫到大家,話不多說直接開始吧,感興趣的朋友可以參考下2024-01-01React?Flux與Redux設(shè)計(jì)及使用原理
這篇文章主要介紹了React?Flux與Redux設(shè)計(jì)及使用,Redux最主要是用作應(yīng)用狀態(tài)的管理。簡(jiǎn)言之,Redux用一個(gè)單獨(dú)的常量狀態(tài)樹(state對(duì)象)保存這一整個(gè)應(yīng)用的狀態(tài),這個(gè)對(duì)象不能直接被改變2023-03-03React Native 集成jpush-react-native的示例代碼
這篇文章主要介紹了React Native 集成jpush-react-native的示例代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08React中super()和super(props)的區(qū)別小結(jié)
本文主要介紹了React中super()和super(props)的區(qū)別小結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2024-03-03create-react-app項(xiàng)目配置全解析
這篇文章主要為大家介紹了create-react-app項(xiàng)目配置全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06