redux 就是react 全域性狀態管理,作用是存放全域性資料
state:存放資料
reducer:修改倉庫資料
是一個函數,引數一:倉庫中的資料,引數2:行為 actions
返回值就是 最新的倉庫資料
就是在reduce中定義的方法,修改資料,相當於mutations
只能是同步方法
actions:派發行為觸發reducer; 語法:sotre.dispatch({type:'add'})
語法:
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 } }
# NPM
npm install redux
# Yarn
yarn add redux
在專案中使用到哪些api
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
在元件中使用倉庫
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
語法:let reducers = combineReducers({屬性:各自的reducer, 屬性:各自的reducer})
使用webpack中的api:require.context 自動獲取到檔案中的暴露的內容
作用:通過該函數可以獲取一個上下文,從而實現工程自動化(遍歷資料夾的檔案,從中獲取指定檔案,自動匯入模組)。在前端工程中,如果一個資料夾中的模組需要頻繁參照時可以使用該中方式一次性引入
語法: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;
作用:實現自動派發,實現行為 reducer 處理方法一一對應
語法:let 物件 = bindActionCreators({屬性:屬性值是一個方法},store.dispatch),屬性值是一個方法 => 就是你的reducer中的方法
實現步驟:
/* 五: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;
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是一個獨立的庫,可以與React、Vue、Angular一直使用,但是它們是相互獨立的;
如果想要同時使用 Redux 和 React,應該使用 React-Redux 來繫結這兩個庫
react-redux是連線react和redux 的橋樑,讓react中使用redux時低耦合,方便快捷 react-redux 提供了兩個 api
作用:提供全域性元件和hooks,在父級元件提供倉庫元件,在自己元件中獲取到倉庫的資料
Provider 為後代元件提供 store
核心:為我們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'});
安裝react-redux
npm install react-redux
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使用
/* 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修改資料,讓資料更新 */
因為reducer 只能處理同步問題,但是我們在工作中,可能需要在倉庫中發生請求,獲取到非同步的資料
在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 這個函數的引數是一個函數 或者 這個函數的返回值是一個函數 // 函數劫持 =》我在處理某個邏輯之前,要做一些操作,我們把這個方法叫做函數劫持
會報錯 => 需要使用 1 中介軟體 2 redux-thunk
redux-thunk =》 作用1:處理非同步action =》 給 非同步action觸發方法,第一個引數 就是dispatch
在store/index.js 檔案中進行設定
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
建立 非同步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 }) } }