<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Redux 狀態(tài)容器、管理

      當你越來越有能力時,自然會有人看得起你;改變自己,你才有自信,夢想才會慢慢的實現(xiàn)。噴泉之所以漂亮是因為她有了壓力;瀑布之所以壯觀是因為她沒有了退路;水之所以能穿石是因為永遠在堅持。

      首先我們要明確一個 React 組件,它與數(shù)據(jù)掛鉤的只有 props 和 state,一個是從上級傳下來的數(shù)據(jù),一個是內部的狀態(tài),只能向下傳,不能直接向上傳。

      這樣的話,我們如何處理同級別組件的通信呢?一個最直接的方式就是創(chuàng)建一個最頂層的 state,把數(shù)據(jù)當作 props 向下傳。這個最頂層的存放 state 的地方,我們可以認為是 store。

      1. Flux 和 Redux

      Flux 是一種架構思想,專門解決軟件的結構問題,它跟 MVC 架構是同一類東西,但是更加簡單和清晰。Flux 存在至少多種實現(xiàn),比如:Redux。

      https://github.com/voronianski/flux-comparison

      Facebook Flux 是用來構建客戶端 Web 應用的應用架構。利用單向數(shù)據(jù)流的方式來組合 React 中的視圖組件。它更像一個模式而不是一個正式的框架,開發(fā)者不需要太多的新代碼就可以快速的上手 Flux。

      中心思想流程:

      • 用戶訪問 View,View 訂閱 Store;
      • View 發(fā)出用戶的 Action;
      • Dispatcher 收到 Action,要求 Store 進行相應的更新;
      • Store 更新后,發(fā)出一個 Change 事件;
      • View 收到 Change 事件后,更新頁面;

      5. Flux.png

      Redux 最主要是用作應用狀態(tài)的管理。簡言之,Redux 用一個單獨的常量狀態(tài)樹(state對象),保存這一整個應用的狀態(tài),這個對象不能直接被改變,當一些數(shù)據(jù)變化了,一個新的對象就會被創(chuàng)建(使用 actions 和 reducers)這樣就可以進行數(shù)據(jù)追蹤,實現(xiàn)時光旅行。

      2. Redux 工作流

      Redux 原理就是訂閱、發(fā)布模式。我們看其中主要的幾個重要的概念:

      • 組件 Component
      • Actions:用戶系統(tǒng)行為,Actions Creators 創(chuàng)建;
      • Store:state 以單一對象存儲在 store 中:
        • 狀態(tài)調度:Store.dispatch(action);
        • 狀態(tài)展示:Store.getState();
        • 訂閱改變: Store.subscribe();
      • Reducers:純處理函數(shù) reducer,里面對老狀態(tài)處理,得到新狀態(tài);

      6. Redux 工作流.png

      點擊組件按鈕觸發(fā)一個事件,通過 Action Creator 創(chuàng)建一個 action 對象。通過 dispatch 把這個 action 對象發(fā)送到 store 里面。在 store 里面 需要通過 reducers 來更新狀態(tài)。store 自己是無法更新狀態(tài)的。reducers 必須接收老的對象和 action,然后根據(jù) action 的 type 不同進行處理,返回新的狀態(tài),新的狀態(tài)更新了,store 就會通知那些訂閱者組件進行更新。

      Redux store 默認將數(shù)據(jù)存儲在內存中,因此?頁面刷新后數(shù)據(jù)會丟失?。這是因為瀏覽器刷新會重新加載整個應用,內存中的狀態(tài)會被重置?。

      Action 文件:

      var increment = () => {
        return {
          type: "increment"
        }
      }
      
      var decrement = () => {
        return {
          type: "decrement"
        }
      }
      
      export { increment, decrement }
      

      Store 文件:

      import { createStore } from "@reduxjs/toolkit";
      import counterReducer from "./reducer";
      
      const Store = createStore(counterReducer)
      
      export default Store 
      

      Reducer 文件:

      const counterReducer = (state, action) => {
        if (state === undefined) {
          return 0
        }
        switch (action.type) {
          case "increment": {
            let newState = state
            newState += 1
            return newState
          }
          case "decrement":{
            let newState = state
            newState -= 1
            return newState
          }
          default:
            return state
        }
      }
      
      export default counterReducer
      

      應用示例:

      import React, { useEffect, useState } from 'react'
      import Store from './1-AppStore/store'
      import { increment, decrement } from './1-AppStore/actions'
      
      export default function ReduxBaseJs() {
        const [count, setcount] = useState(Store.getState())
        useEffect(()=>{
          Store.subscribe(() => {
            console.log(Store.getState())
            setcount(Store.getState())
          })
        })
        
        return (
          <div>
            <div>
              <button
                aria-label="Increment value"
                onClick={() => Store.dispatch(increment())}
              >
                Increment
              </button>
              <span>{count}</span>
              <button
                aria-label="Decrement value"
                onClick={() => Store.dispatch(decrement())}
              >
                Decrement
              </button>
            </div>
          </div>
        )
      }
      

      3. Redux 使用三大原則

      • state 以單一對象存儲在 store 對象中;
      • state 只讀,每次更新都是返回一個新的對象;
      • 使用純函數(shù) reducer 執(zhí)行 state 更新;
        • 對外界沒有副作用。即調用后對外界變量、對象沒有影響。
        • 同樣的輸入得到同樣的輸出。

      4. 你需要使用 Redux 嗎?

      雖然 Redux 是一個很有價值的管理狀態(tài)工具,但還是要考慮下它是否適合你的場景。不要僅僅因為有人說過應該使用 Redux 而使用 - 應該花一些時間來了解使用它的潛在好處和取舍。當遇到如下問題時,建議開始使用 Redux:

      • 你有很多數(shù)據(jù)隨時間而變化;
      • 你希望狀態(tài)有一個唯一確定的來源(single source of truth);
      • 你發(fā)現(xiàn)將所有狀態(tài)放在頂層組件中管理已不可維護;

      5. Redux 使用之 Reducer 函數(shù)拆分 combineReducers

      應用的整體全局狀態(tài)以對象樹的方式存放于單個 store。 唯一改變狀態(tài)樹(state tree)的方法是創(chuàng)建 action,一個描述發(fā)生了什么的對象,并將其 dispatch 給 store。 要指定狀態(tài)樹如何響應 action 來進行更新,你可以編寫純 reducer 函數(shù),這些函數(shù)根據(jù)舊 state 和 action 來計算新 state。

      Redux 擴展(行為拆分),如果不同的 Action 所處理的屬性之間沒有聯(lián)系,我們可以把 Reducer 函數(shù)拆分。不同的函數(shù)負責處理不同屬性,最終把它們合并成一個大的 Reducer 即可。那在 dispatch(action) 的時候是怎么知道用那個 reducer 來處理的呢?所有的 reducer 都會執(zhí)行一遍,其實就是所有的 reducer 輪詢匹配。

      store.js 文件:

      // 創(chuàng)建合并 Reducer
      import {combineReducers} from "redux";
      const reducer = combineReducers ({
        aReducer,
        bReducer,
        cReducer
      })
      const store = createStore(reducer)
      

      訪問:

      // 訪問:
      store.getState.aReducer.property // 不同的命名空間
      

      TS 示例:

      reducer.ts 文件:

      // 定義一個 Reducer 純函數(shù)
      const counterReducer = (state: any, action: any) => {
        if (state === undefined) {
          return 0
        }
        switch (action.type) {
          case "increment": {
            let newState = state
            newState += 1
            return newState
          }
          case "decrement":{
            let newState = state
            newState -= 1
            return newState
          }
        
          default:
            return state
        }
      }
      export default counterReducer
      

      actions.ts 文件:

      // 定義相關行為 action
      var increment = () => {
        return {
          type: "increment"
        }
      }
      var decrement = () => {
        return {
          type: "decrement"
        }
      }
      export { increment, decrement }
      

      store.ts 文件:

      import { createStore } from "@reduxjs/toolkit";
      import counterReducer from "./reducer";
      
      const Store = createStore(counterReducer)
      
      export default Store
      

      component.ts 文件:

      import React, { useEffect, useState } from 'react'
      import Store from './2-AppStore/store'
      import { increment, decrement } from './2-AppStore/actions'
      
      export default function ReduxBaseTs() {
        const [count, setcount] = useState(Store.getState())
        useEffect(() => {
          Store.subscribe(() => {
            console.log(Store.getState())
            setcount(Store.getState())
          })
        })
      
        return (
          <div>
            <div>
              <button
                aria-label="Increment value"
                onClick={() => Store.dispatch(increment())}
              >
                Increment
              </button>
              <span>{count}</span>
              <button
                aria-label="Decrement value"
                onClick={() => Store.dispatch(decrement())}
              >
                Decrement
              </button>
            </div>
          </div>
        )
      }
      

      ??:以上基礎使用方法已經(jīng)不是官方推薦的編寫方式了,現(xiàn)在推薦使用 Redux Toolkit 編寫 Redux 邏輯的方法。

      6. React-redux

      其實 Redux 和 React 沒有任何關系,它是基于 Flux 實現(xiàn)的一套可用于 React 狀態(tài)管理的庫。而 React-redux 是基于 Redux 庫(必須引入、依賴 Redux),在 Redux 基礎上多了一點 React 特性。幫你構建父組件以及訂閱和發(fā)布這樣的一些事情。這樣在 React 中狀態(tài)管理使用更加方便。

      React-redux 在 Redux 基礎上,通過 connect 高階函數(shù)生成高階組件(父組件)包裝訂閱、發(fā)布功能(幫你訂閱和取消訂閱),不用開發(fā)者自己發(fā)起訂閱和發(fā)布。其次通過最外層 Provider 供應商組件負責把 store 跨級給 connect 組件,原理就是通過 context 一級一級將 store 傳遞給 connect 組件。即通過 connect 包裝就將 App UI 組件變成了容器組件,之前的組件就變成了 UI 組件。具體應用參考 Redux 中文官網(wǎng)

      https://github.com/reduxjs/react-redux

      Redux Toolkit 一般在 React 項目中結合 React-redux 使用。

      》UI 組件與容器組件:

      1)UI 組件

      • 只負責 UI 的呈現(xiàn),不帶有任何業(yè)務邏輯;
      • 沒有狀態(tài)(即不使用 this.state 這個變量),所有數(shù)據(jù)都由參數(shù)(this.props)提供;
      • 不使用任何 Redux 的 API;

      2)容器組件

      • 負責管理數(shù)據(jù)和業(yè)務邏輯,不負責 UI 的呈現(xiàn);
      • 帶有內部狀態(tài);
      • 使用 Redux 的 API;

      》高階組件(HOC:Higher order components) 與 context 通信在 react-redux 底層中的應用:

      • connect 是 HOC,高階組件;
      • Provider 組件,可以讓容器組件拿到 state,使用了context;

      高階組件構建與應用:HOC 不僅僅是一個方法,確切說應該是一個組件工廠,獲取低階組件,生成高階組件。

      • 代碼復用,代碼模塊化;
      • 增刪改 props;
      • 渲染劫持;

      7. Redux ToolKit

      Redux Toolkit 簡化了編寫 Redux 邏輯和設置 store 的過程。 使用 Redux Toolkit,相同的示例邏輯如下所示。更詳細使用可以參考 Demo 工程和 Redux 中文官網(wǎng)

      相關 API:

      • createSlice;
      • configureStore;

      TS 示例:

      import { createSlice, configureStore } from '@reduxjs/toolkit'
      
      const counterSlice = createSlice({
        name: 'counter',
        initialState: {
          value: 0
        },
        reducers: {
          incremented: state => {
            // Redux Toolkit 允許在 reducers 中編寫 "mutating" 邏輯。
            // 它實際上并沒有改變 state,因為使用的是 Immer 庫,檢測到“草稿 state”的變化并產(chǎn)生一個全新的
            // 基于這些更改的不可變的 state。
            state.value += 1
          },
          decremented: state => {
            state.value -= 1
          }
        }
      })
      
      export const { incremented, decremented } = counterSlice.actions
      
      const store = configureStore({
        reducer: counterSlice.reducer
      })
      
      // 可以訂閱 store
      store.subscribe(() => console.log(store.getState()))
      
      // 將我們所創(chuàng)建的 action 對象傳遞給 `dispatch`
      store.dispatch(incremented())
      // {value: 1}
      store.dispatch(incremented())
      // {value: 2}
      store.dispatch(decremented())
      // {value: 1}
      

      8. Redux 中間件

      在 redux 中,action 僅僅是攜帶了數(shù)據(jù)的普通 js 對象。action creator 返回的值是這個 action 類型的對象。然后通過 store.dispatch() 進行分發(fā)。同步情況下一切都很完美,但是 reducer 無法處理異步的情況。那么我們就需要在 action 和 reducer 中間架起一座橋梁來處理異步。這就是 middleware。

      中間件的由來與原理、機制:

      export default function thunkMiddleware({ dispatch, getstate }) {
        return next => action =>
          typeof action === 'function'? 
            action (dispatch, getstate):
            next (action);
      }
      

      這段代碼的意思是,中間件這個橋梁接受到的參數(shù) action,如果不是 function 則和過去一樣直接執(zhí)行 next 方法(下一步處理),相當于中間件沒有做任何事。如果 action 是 function,則先執(zhí)行 action,action 的處理結束之后,再在 action 的內部調用 dispatch。

      8.1 redux-thunk

      到目前為止,我們學習到所有邏輯都是同步的。我們需要一個地方在我們的 Redux 應用程序中放置異步邏輯。這就需要使用中間件 redux-thunk。

      thunk 是一種特定類型的 Redux 函數(shù),可以包含異步邏輯。Thunk 是使用兩個函數(shù)編寫的:

      • 一個內部 thunk 函數(shù),它以 dispatchgetState 作為參數(shù);
      • 外部創(chuàng)建者函數(shù),它創(chuàng)建并返回 thunk 函數(shù);

      counterSlice 導出的函數(shù)就是一個 thunk action creator 的例子。

      // 下面這個函數(shù)就是一個 thunk ,它使我們可以執(zhí)行異步邏輯
      // 你可以 dispatched 異步 action `dispatch(incrementAsync(10))` 就像一個常規(guī)的 action
      // 調用 thunk 時接受 `dispatch` 函數(shù)作為第一個參數(shù)
      // 當異步代碼執(zhí)行完畢時,可以 dispatched actions
      export const incrementAsync = amount => dispatch => {
        setTimeout(() => {
          dispatch(incrementByAmount(amount))
        }, 1000)
      }
      

      我們可以像使用普通 Redux action creator 一樣使用它們:

      store.dispatch(incrementAsync(5))
      

      8.2 redux-promise

      Redux 異步邏輯另外一種解決方案 redux-promise 中間件。用 promise 對象代替 Redux-thunk 中的函數(shù)。

      8.3 redux-saga

      redux-saga 相比 redux-thunk、redux-promise 能夠非侵入式結合 redux 進行開發(fā)。讓你的 action 還是之前那個普通的 action 對象,然后你需要引入我 saga 中的一些任務、effect 作用等等來處理。

      8.3.1 生成器函數(shù) Generator

      Generator 生成器函數(shù),ES6 中提供異步編程的一種解決方案。有時候也被被人稱為狀態(tài)機,可以讓函數(shù)中斷執(zhí)行,等你需要推一步就走一步,可以生成輸出多個狀態(tài),所以又叫狀態(tài)機。

      生成器函數(shù)特征:

      1. 函數(shù)名前面增加 * 號。
      2. 必須使用關鍵字 yield(產(chǎn)出狀態(tài)值)。
      3. yield 后面跟的是狀態(tài)機生成的狀態(tài)。即當遇到 yield 表達式,就暫停執(zhí)行后面的操作,并將緊跟在yield后面的那個表達式的值,作為返回的對象的 value 屬性值。yield 表達式本身沒有返回值,或者說總是返回undefined。
      4. next 方法可以帶一個參數(shù),該參數(shù)就會被當作上一個 yield 表達式的返回值。
      function *test() {
        console.log("111111")
        yield;
        console.log("222222")
        yield;
        console.log("333333")
        yield;
      }
      
      let generator = test()
      // next() 執(zhí)行器函數(shù)執(zhí)行一次,直到遇到 yield 關鍵字
      generator.next() // 111111
      generator.next() // 222222
      generator.next() // 333333
      generator.next() // 沒有任何輸出了,已經(jīng)結束了
      
      
      function *test1() {
        console.log("111111")
        let value1 = yield "yield return 1 step";
        console.log("222222", value1)
        let value2 = yield "yield return 2 step";
        console.log("333333", value2)
        let value3 = yield "yield return 3 step";
        console.log("333333", value3)
      }
      
      let generator1 = test1()
      
      let gen1 = generator1.next("1 next 參數(shù)")
      console.log(gen1) // {value: 'yield return 1 step', done: false}
      let gen2 = generator1.next("2 next 參數(shù)")
      console.log(gen2) // {value: 'yield return 2 step', done: false}
      let gen3 =generator1.next("3 next 參數(shù)")
      console.log(gen3) // {value: 'yield return 3 step', done: false}
      
      let gen4 =generator1.next("4 next 參數(shù)")
      console.log(gen4) // {value: undefined, done: true}
      

      異步鏈式調用更簡單的寫法 async-await 寫法,async-await 本質是生成器的一套語法糖,內置了執(zhí)行器函數(shù)。讓異步變寫得和同步的一樣簡單。但是這里 redux-saga 是基于生成器函數(shù)來實現(xiàn)的,我們了解即可:

      async function test() {
        var res1 = await fetch();
        var res2 = await fetch(res1);
        var res3 = await fetch(res2);
      }
      
      8.3.2 redux-saga 應用

      在 saga 中,全局監(jiān)聽器和接收器使用 Generator 函數(shù)和 saga 自身的一些輔助函數(shù)實現(xiàn)對整個流程的管控。

      7. redux-saga.png

      // Component 組件內部
      dispatch({action:"get-list"})
      
      // WatcherSaga
      // saga.js 文件
      function *watchSaga() {
        while(true) {
          // take 監(jiān)聽 組件發(fā)來的 action
          yield take("get-list")
          // fork 同步非阻塞執(zhí)行函數(shù) getList
          yield fork(getList)
        }
      }
      
      function *getList() {
        // 異步處理:call 函數(shù)發(fā)布異步請求 - 阻塞式調用
        let res = yield call(getListAction) //這里傳入返回值是promise對象的函數(shù)
        // put 函數(shù)發(fā)出新的 action
        yield put({
          type: "change-list",
          payload: res
        })
      }
      
      function getListAction() {
        return new Promise((resolve, reject)=>{
          setTime(()={
            resolve(["111","222","333"])
          },2000)
        })
      }
                           
      export default watchSage
      
      // store.js 文件
      
      import {createStore, applyMiddleware} from 'redux'
      import reducer from ' /reducer'
      import createSagaMidlleWare from 'redux-saga'
      import watchSaga from ?/ saga'
      
      const SagaMidlleWare = createSagaMidlleWare()
      const store = createStore(reducer, applyMiddleware(SagaMidlleWare))
      
      SagaMidlleWare.run(latchSaga) //saga 任務,
      export default store
      

      多任務同時監(jiān)聽 all:

      // WatcherSaga
      // saga2.js 文件                  
      export default watchSage
      
      // 聚合統(tǒng)一監(jiān)聽多個任務 saga.js 文件
      import {all} from 'redux-saga/effects'
      import watchSagal from '?/saga/sagal'
      import watchSaga2 from './saga/saga2'
      function *watchSaga(){
      	yield all([watchSaga1(),watchSaga2()])
      }
      export default watchSaga
      

      多異步鏈式流程調用:

      function *getList() {
        // 異步處理:call 函數(shù)發(fā)布異步請求 - 阻塞式調用
        let res = yield call(getListAction) //這里傳入返回值是promise對象的函數(shù)
        let res1 = yield call(getListAction1, res)
        // put 函數(shù)發(fā)出新的 action
        yield put({
          type: "change-list",
          payload: res1
        })
      }
      
      function getListAction() {
        return new Promise((resolve, reject)=>{
          setTime(()={
            resolve(["111","222","333"])
          },2000)
        })
      }
                           
      function getListAction1(data) {
        return new Promise((resolve, reject)=>{
          setTime(()={
            resolve([...data, "444"])
          },2000)
        })
      }
                           
      export default watchSage
      

      watchSaga 函數(shù)新寫法-合并 take 和 fork:

      // WatcherSaga
      // saga.js 文件
      function *watchSaga() {
        /*while(true) {
          // take 監(jiān)聽 組件發(fā)來的 action
          yield take("get-list")
          // fork 同步非阻塞執(zhí)行函數(shù) getList
          yield fork(getList)
        }*/
        yield takeEvery("get-list", getList)
      }
      
      8.3.3 redux-saga 應用場景

      在 React-Redux 應用中,?redux-saga 主要用于管理復雜異步邏輯和副作用?,尤其在以下場景中具有顯著優(yōu)勢:

      ?多步驟異步操作:?當操作涉及多個順序/并行的異步任務(如:登錄 → 獲取用戶信息 → 加載權限列表),sagaGenerator 函數(shù)可用 yield 精確控制每一步流程,避免回調地獄?

      function* loginFlow() {
        yield call(loginAPI);        // 步驟1:登錄
        yield call(fetchUserInfo);   // 步驟2:獲取用戶信息
        yield call(loadPermissions); // 步驟3:加載權限
      }
      

      ?依賴異步結果的后續(xù)操作:若后續(xù)操作需依賴多個異步任務結果(如:支付需同時驗證賬戶余額和風控狀態(tài)),saga 可通過 all 實現(xiàn)并行請求,并統(tǒng)一處理結果?。

      優(yōu)選 saga 的場景:?多步驟異步?、?高可測性要求?、?長時運行任務?(如實時通信)?。

      簡單場景(單一請求)可使用 redux-thunk 或 Redux Toolkit 內置方案?。

      9. Redux 插件

      9.1 redux-persist

      redux-persist 是一個用于 Redux 狀態(tài)管理的持久化插件,允許將應用狀態(tài)保存到本地存儲(如 localStorage),以便在應用重啟或頁面刷新時恢復狀態(tài)。必須配合 React-redux 使用。

      posted @ 2025-07-30 17:11  背包の技術  閱讀(166)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 亚洲成av一区二区三区| 亚洲AV国产福利精品在现观看| 竹菊影视欧美日韩一区二区三区四区五区| 久久精品道一区二区三区| 五月天天天综合精品无码| 国产一区二区在线有码| 国产热A欧美热A在线视频| 狠狠色噜噜狠狠狠狠7777米奇 | 一区二区免费高清观看国产丝瓜| 亚洲av尤物一区二区| 久久精品亚洲日本波多野结衣 | 一区天堂中文最新版在线| 狠狠色狠狠色综合日日不卡| 啊灬啊灬啊灬快灬高潮了电影片段| 成人做受120秒试看试看视频| 青青草国产精品一区二区| 综合偷自拍亚洲乱中文字幕| 无码吃奶揉捏奶头高潮视频| 久久av无码精品人妻出轨| 91亚洲一线产区二线产区| 久久人妻无码一区二区三区av| 性人久久久久| 视频一区视频二区卡通动漫| 国产成人亚洲无码淙合青草| 91老肥熟女九色老女人| 精品人妻中文字幕av| 高清无码18| 2020国产欧洲精品网站| 99久久精品一区二区国产| av新版天堂在线观看| 欧美日韩中文字幕视频不卡一二区| 人妻少妇偷人精品免费看| 国产精品久久久久鬼色| 日本免费人成视频在线观看 | 欧美日本精品一本二本三区| 在线播放国产女同闺蜜| 华人在线亚洲欧美精品| 久热这里只有精品视频六| 日本视频一两二两三区| 天天爽夜夜爽人人爽曰| 亚洲av无码成人精品区一区 |