react中redux怎麼使用

2023-02-20 21:02:05

一、redux是什麼?

redux 就是react 全域性狀態管理,作用是存放全域性資料

 

二、核心

  1. state:存放資料

  2. reducer:修改倉庫資料

  • 是一個函數,引數一:倉庫中的資料,引數2:行為 actions

  • 返回值就是 最新的倉庫資料

  • 就是在reduce中定義的方法,修改資料,相當於mutations

  • 只能是同步方法

  1. actions:派發行為觸發reducer; 語法:sotre.dispatch({type:'add'})

  2. 語法:

function  reducer( state={age:10,name:'lisa' },actions){
        switch(action.type){
            case "add":
                return {...state,  age:state.age+1 };
            case "reduce":
                return { age:state.age-1 }
            default:
                return state
        }
    }

 

三、使用redux

1、安裝React-redux
# NPM
npm install redux

# Yarn
yarn add redux
2、在src目錄下建立store資料夾,index.js檔案

在專案中使用到哪些api

  1. createStore

    • 作用:建立倉庫

    • 語法:let store=createStore(reducer,中介軟體);

    • 輸出store:

      • @@observable: ƒ observable() 觀察倉庫中的資料、

      • dispatch: ƒ dispatch(action) 觸發reducer、

      • getState: ƒ getState()獲取到倉庫中的資料、

      • replaceReducer: ƒ replaceReducer(nextReducer) 替換reducer、

      • subscribe: ƒ subscribe(listener) 訂閱

//建立倉庫

import {createStore} from 'redux'


// createStore=>建立倉庫
//語法
 //let store = createStore(reducer,中介軟體)


 // reducer =>  自己定義

 // 1他是一個函數
 // 2引數1 倉庫中的資料   引數2 行為 actions
 // 3這個reduer 返回值 就是最新的倉庫中的資料 
 // 4redcuer =》就是在reducer中定義方法修改資料 =》vuex mutations


 function reducer(state={age:10},actions){
      switch(actions.type){
        case "add":
            console.log('add',state);
            return {age:state.age+1};
         default :
         return state
      }
 }

 let store = createStore(reducer)


/**
 * 
 * @@observable: ƒ observable()  觀察倉庫中的資料
dispatch: ƒ dispatch(action)  =》觸發reducer
getState: ƒ getState()  =>獲取到倉庫中的資料
replaceReducer: ƒ replaceReducer(nextReducer)  替換reducer
subscribe: ƒ subscribe(listener)  訂閱
 * 
 * 
 * 
 * **/

   export default store
3、在App.js根元件中使用倉庫
  1. 在元件中使用倉庫

    1. 引入倉庫 import store from './store/index'

  2. 獲取倉庫中的資料:store.getState().meReducer.age; (meReducer.age指的是meReducer中的age屬性)

  3. 觸發reducer:store.dispatch({type:"add"})

import logo from './logo.svg';
import './App.css';
// 在元件中引入倉庫
import store from './store/index'
import {useState} from 'react'

function App() {
 // 1獲取到倉庫中的資料
  // console.log(store.getState());
  // let age = store.getState().age
  let [age,setAge] = useState(store.getState().age)

  const changeAge = ()=>{
     //觸發 reducer
     store.dispatch({type:'add'})
    //  問題=》倉庫中的資料更新了=》但是檢視沒有更新 =》元件沒有更新
    // 1 講這個資料=》動態資料
    // setAge(倉庫中的最新資料) =>和倉庫進行關聯
    setAge(store.getState().age)
  }
  return (
    <div className="App">
       <h2>我的年齡{age}</h2>
       <button onClick={()=>changeAge()}>修改倉庫選中資料</button>
    </div>
  );
}

export default App;

 

四、combineReducers 合併reducer

combineReducers:

  1. 作用:合併reducer

  2. 語法:let reducers = combineReducers({屬性:各自的reducer, 屬性:各自的reducer})

使用webpack中的api:require.context 自動獲取到檔案中的暴露的內容

  1. 作用:通過該函數可以獲取一個上下文,從而實現工程自動化(遍歷資料夾的檔案,從中獲取指定檔案,自動匯入模組)。在前端工程中,如果一個資料夾中的模組需要頻繁參照時可以使用該中方式一次性引入

  2. 語法:let webf = require.context('檔案路徑',布林值,正則)

返回值: 1 webf.keys() 返回一個陣列,由匹配成功的檔案所組成的陣列 2 webf(路徑).default 獲取到路徑中匯出的模組

手動合併reducer

//  合拼reducer

import {combineReducers} from 'redux'

// combineReducers
import CartReducer from './CartReducer'
import meReducer from './meReducer'
//作用:合拼reducer
//語法: let reducers = combineReducers({屬性:各自的reducer,屬性:各自的reducer})


let reducers = combineReducers({
    CartReducer,
    meReducer
})

export default reducers

工程化處理reducer 合拼

/* 
    combineReducer
        作用: 合併 reducer 資料實現模組化
        語法:let reducers=combineReducers({屬性:各自的reducer, 屬性:各自的reducer})
*/

// 工程化處理Reducer 合拼

import { combineReducers } from "redux";

// combineReducers
import CartReducer from "./CartReducer";
import MeReducer from "./MeReducer";
// 在這裡引入各自的reducer
// 處理方法 =》 自動引入reducer 自動合拼reducer

// 1 在reducers資料夾下建立一個 reducer 檔案 =》 再給我 合拼成reducer

// 1 webpack =》 require.context =》自動獲取到檔案中的暴露內容

// 語法:require.context('檔案路徑',布林值,正則)
// requeire.context('檔案路徑',布林值,正則)  => 返回值  (是webpack)範例方式

// 兩個方法 1. webf.keys()=>['檔案路徑',布林值,正則]
// 2.獲取到它的內容 webf(路徑).default

let webf = require.context("./", true, /\.js/);
let webfList = webf.keys();
// console.log(webfList);
// 刪除自身 index.js
let index=webfList.findIndex((item,index)=>{
    return item=='./index.js'
})
webfList.splice(index,1)
// console.log(webfList);

// 將webfList合併成一個物件
let objs={};
webfList.forEach((item,index)=>{// 檔案路徑     ./ CartReducer .js
        // console.log(webf(item).default);
        // 處理屬性 = item
        let items=item.replace('./','').replace('.js','')
        // console.log(items)
        objs[items]=webf(item).default
})
// console.log(objs)

// 作用:合併reducer
// 語法:let reducers=combineReducers({屬性:各自的reducer,屬性:各自的reducer})

let reducers = combineReducers(objs);

export default reducers;

 

五、bindActionCreators 自動觸發reducer

  1. 作用:實現自動派發,實現行為 reducer 處理方法一一對應

  2. 語法:let 物件 = bindActionCreators({屬性:屬性值是一個方法},store.dispatch),屬性值是一個方法 => 就是你的reducer中的方法

  3. 實現步驟:

/* 
    五:bindActionCreators

    bindActionCreators => 自動觸發reducer => 你想要觸發

    語法:let 物件 =bindActionCreators({屬性:屬性值是一個方法},dispatch)  屬性值是一個方法=》 就是你的reducers中的方法


    使用: 
        1 實現reducer 和他的行為一一對應
        2 使用 bindActionCreators 來實現
            2.1 語法 bindActionsCreators({就是你的reducer 和 使用的行為對應},dispatch)

         全部觸發我的模板中的reducer 行為
             1 我的模組reducer 有多少個行為
             2 我的模組中add
        
    */

import { bindActionCreators } from "redux";
import store from "../index";

// bindActionCreators => 自動觸發reducer => 你想要觸發
// 語法 let物件 =bindActionCreators({屬性:屬性值是一個方法},dispatch),屬性值是一個方法 =》就是你的reducer中的方法

// 建立方法
let meAdd = () => {
  return {
    // 行為 =》 actions
    type: "add",
  };
};

let meSub = () => {
  return {
    type: "sub",
  };
};

let meActions = bindActionCreators({ meAdd, meSub }, store.dispatch);

export default meActions;
  1. 引入這個自動派發的方法 :直接使用

import logo from './logo.svg';
import './App.css';
//來到元件
import store from './store/index'
import {useState} from 'react'

//使用 自動派發
import meActions from './store/actions/meActions'

function App() {
 // 1獲取到倉庫中的資料
  console.log(store.getState());
  // let age = store.getState().meReducer.age
  let [age,setAge] = useState(store.getState().meReducer.age)

// 3引入我們這個自動派發的方法 =》直接使用
  const changeAge = ()=>{
      console.log( meActions);
    //  store.dispatch({type:'add'}) //觸發reducer
    meActions.meAdd()
 
    setAge(store.getState().meReducer.age)
  }

  return (
    <div className="App">
       <h2>我的年齡{age}</h2>
       <button onClick={()=>changeAge()}>修改倉庫選中資料</button>
    </div>
  );
}

export default App;

 

六、React Redux

1、為什麼應該使用React-Redux?

因為React是一個獨立的庫,可以與React、Vue、Angular一直使用,但是它們是相互獨立的;

如果想要同時使用 Redux 和 React,應該使用 React-Redux 來繫結這兩個庫

react-redux是連線react和redux 的橋樑,讓react中使用redux時低耦合,方便快捷 react-redux 提供了兩個 api

  1. 作用:提供全域性元件和hooks,在父級元件提供倉庫元件,在自己元件中獲取到倉庫的資料

  2. Provider 為後代元件提供 store

  3. connect 為元件提供資料和變更⽅法

核心:為我們react專案提供的一個元件,兩個hooks

元件:Provider 1 作用:在父級元件中提供資料 ,其他的子集元件就可以獲取到;

2 在父元件中提供了資料 store;

hooks:

useSelector 1 作用:在元件中獲取倉庫中的資料,再通過useState修改資料方法,讓資料更新

2 語法:useSelector(state => { return 返回值}) // 返回 在倉庫中獲取的資料

useDispatch 1 作用:可以獲取到更新元件的dispatch,先觸發reducer,

2 語法:let dispatch=useDispatch(); dispatch({type:'add'});

 

2、在專案中使用redux

  1. 安裝react-redux

npm install react-redux

  2.在入口檔案中使用Provider提供倉庫store

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    {/* 在父元件中提供資料 */}
    <App />
  </Provider>
);

3.useSelector使用

4.useDispatch使用

/* 
   react-redux 作用
      提供 1 元件 =》 在子級元件提供倉庫元件,在自己元件中獲取到倉庫資料
      2 hooks  

      useSelector => 得到倉庫中的資料
      // 語法
      useDispatch 作用:可以獲取到更新元件的dispatch;觸發 reducer  =》 語法 useDispatch() => dispatch()
*/

// 使用
// 在自己元件中獲取到倉庫中的資料 =》 使用它提供的兩個hooks
import {useSelector,useDispatch} from 'react-redux' 
// useSelector(state=>{返回值}) =》返回值  得到倉庫中的資料
// useDispatch 觸發redcuer =》 語法 useDispatch()=> 的返回值就是 dispatch()
      // 作用:獲取到可以更新元件的dispatch

function App(){
  let age=useSelector(state=>{  // state是來自父元件的store資料
    return state.MeReducer.age
  })

  let dispatch=useDispatch() // 1 先觸發reducer,獲取到倉庫中的資料,再通過useState修改資料方法,讓資料更新
  console.log(age,'元件重新建立');

  return(
      <div>
          <h2>我的年齡{age}</h2>
          <button onClick={()=>{dispatch({type:'add'})}}>修改倉庫</button>
      </div>
  )

}

export default App

/* 
  總結:react-redux
      作用:讓倉庫和react專案進行關聯
            它為react專案提供了一個元件(Provider),兩個hooks(useSelector、useDispatch)
      Provider: 在父級元件中提供資料,其他的自己元件就可以獲取到
      useSelector:在元件獲取到倉庫中的資料
      useDispatch:先觸發reducer,獲取到倉庫中的資料,再通過useState修改資料,讓資料更新

*/

 

七、非同步actions

1、為什麼需要處理非同步?

因為reducer 只能處理同步問題,但是我們在工作中,可能需要在倉庫中發生請求,獲取到非同步的資料

2、非同步actions作用?

1)在倉庫中獲取非同步收據 2)觸發reducer 修改倉庫中的資料

3、實現非同步actions?
  1. 在store資料夾下建立一個 actions 資料夾,實現 非同步actions 和各自的reducer 一一對應

//我的模組中 非同步處理
import axios from 'axios'
import store from '../index'
 // 定義非同步處理方法

 //根據actions作用來進行定義 =》1 獲取到非同步資料   2 觸發reducer

 //定義非同步處理方法
 // 1 是一個方法
 // 2 獲取到非同步資料
 // 3 觸發reducer   => store
  export  function   getAgeSub(){
       
     //1獲取到非同步資料
     function getData(){
        return  axios.get('').then(res=>{ //後端給的資料
              let a = 100
              return a
          })
     }

     // 2觸發reducer
     return  async()=>{
          // 1獲取到非同步資料
        let data =   await getData()
        console.log(data);
          // 2 觸發reducer =>將非同步資料傳遞給 reducer
          console.log('觸發reducer');
          store.dispatch({type:'add',data })
     }
 }

 // getAgeSub()

 //總結 定義actions 
 //1 獲取到非同步資料
 //2 觸發reducer
 //3 知道執行的獲取到非同步資料,再 執行reducer

 //定義非同步actions => 函數劫持
//高階函數=》  1 這個函數的引數是一個函數  或者 這個函數的返回值是一個函數
 // 函數劫持 =》我在處理某個邏輯之前,要做一些操作,我們把這個方法叫做函數劫持
4 、在元件中使用 dispatch 觸發非同步actions

會報錯 => 需要使用 1 中介軟體 2 redux-thunk

redux-thunk =》 作用1:處理非同步action =》 給 非同步action觸發方法,第一個引數 就是dispatch

5、設定中介軟體 =》redux-thunk
  1. 在store/index.js 檔案中進行設定

  2. 安裝redex-thunk

npm install redux-thunk
// 引入中介軟體
import {createStore,applyMiddleware} from 'redux'
import reducers from './reducers'
// 引入'redux-thunk'
import ReduxThunk from 'redux-thunk'



let store = createStore(reducers,applyMiddleware(ReduxThunk))
  //applyMiddleware(ReduxThunk) =>1處理元件中 dispatch()這個方法內容可以寫 方法 
  // 2 非同步actions 返回的處理方法 的第一次引數就是dispatch


export default store
6、在其他元件中觸發非同步actions

建立 非同步actions 返回的處理方法 的第一次引數就是dispatch

export  function   getAgeReduce(){
       
    //1獲取到非同步資料
    function getData(){
       return  axios.get('').then(res=>{ //後端給的資料
             let a = 100
             return a
         })
    }

    // 2觸發reducer
    return  async(dispatch)=>{ //第一個引數 就是  dispatch
         // 1獲取到非同步資料
       let data =   await getData()
       console.log(data);
         // 2 觸發reducer =>將非同步資料傳遞給 reducer
         console.log('觸發reducer');
      
        dispatch({type:'reduce',data })
    }
}

 

總結