store 目錄下
store/reducer.js
import * as actionTypes from './constants' const initalState = { counter: 100 , banners: [ ] , recommends: [ ]
}
function reducer ( state = initalState, action ) { switch ( action. type) { case actionTypes. ADD_NUMBER : return { ... state, counter: state. counter + action. num } case actionTypes. SUB_NUMBER : return { ... state, counter: state. counter - action. num } case actionTypes. CHANGE_BANNERS : return { ... state, banners: action. banners } case actionTypes. CHANGE_RECOMMENDS : return { ... state, recommends: action. recommends } default : return state}
} export default reducer
store/index.js
import { createStore, applyMiddleware } from 'redux' ` redux-thunk:一個流行的Redux中間件,允許 dispatch 函數(而不僅是對象) `
import { thunk } from 'redux-thunk' import reducer from './reducer' ` 默認情況下,Redux的store.dispatch(object),只能是object,不能是function使用 redux-thunk 可以增強store,就能 store.dispatch(function)store.dispatch(function) store.dispatch一個函數,這個函數會被中間件自動執行! `
` 當需要更多的中間件時,只需:applyMiddleware(thunk, xxx, xxx, xxx) 即可 `
const store = createStore ( reducer, applyMiddleware ( thunk) ) export default store
store/actionCreators.js
(這里的方法們,是在 .jsx組件中使用的)
import * as actionTypes from './constants'
import axios from 'axios' export const addNumberAction = num => ( { type: actionTypes. ADD_NUMBER , num
} ) export const subNumberAction = num => ( { type: actionTypes. SUB_NUMBER , num
} ) export const changeBannersAction = banners => ( { type: actionTypes. CHANGE_BANNERS , banners
} ) export const changeRecommendsAction = recommends => ( { type: actionTypes. CHANGE_RECOMMENDS , recommends
} ) export const fetchHomeMultidataAction = ( ) => { function foo ( dispatch, getState ) { axios. get ( 'http://121.200.320.20:8180/home/multidata' ) . then ( res => { const banners = res. data. data. banner. listconst recommends = res. data. data. banner. listdispatch ( changeBannersAction ( banners) ) dispatch ( changeRecommendsAction ( recommends) ) } ) } return foo
}
src 下的 index.js
src/index.js
import React from 'react'
import ReactDOM from 'react-dom/client' ` * 步驟1 - 通過 react-redux 庫的高階組件,減少使用過程中 .jsx文件中的冗余代碼* Provider :react-redux 庫的高階組件,用于將 Redux 的 store 傳遞給整個 React 應用,* Provider 必須包裹根組件(如:<App />),并傳入 store 作為 prop。 `
import { Provider } from 'react-redux'
` 2 - import 你的 store `
import store from './store' import App from './App' const root = ReactDOM. createRoot ( document. getElementById ( 'root' ) ) root. render ( < React. StrictMode> ` 3 - 必須傳入一個store ` < Provider store= { store} > < App / > < / Provider> ` 4 - 在具體的.jsx組件中,在子組件(如 about.jsx)中,通過 connect 函數或 useSelector 鉤子連接 Redux store,無需手動導入 store。 ` < / React. StrictMode>
)
category.jsx
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { fetchHomeMultidataAction } from '../store/actionCreators' export class Category extends PureComponent { componentDidMount ( ) { this . props. fetchHomeMultidata ( ) } render ( ) { return ( < div> < h2> Catefory Page< / h2> < / div> ) }
} const mapDispatchToProps = dispatch => ( { fetchHomeMultidata ( ) { dispatch ( fetchHomeMultidataAction ( ) ) }
} ) export default connect ( null , mapDispatchToProps) ( Category)
about.jsx
【含 connect 詳解】
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { addNumberAction, subNumberAction } from '../store/actionCreators' export class About extends PureComponent { calcNumber ( num, isAdd ) { if ( isAdd) { this . props. addNumber ( num) } else { this . props. subNumber ( num) } } render ( ) { const { counter, banners, recommends } = this . propsreturn ( < div> < h2> about: { counter} < / h2> < div> < button onClick= { e => this . calcNumber ( 6 , true ) } > + 6 < / button> < button onClick= { e => this . calcNumber ( 88 , true ) } > + 88 < / button> < button onClick= { e => this . calcNumber ( 6 , false ) } > - 6 < / button> < button onClick= { e => this . calcNumber ( 88 , false ) } > - 88 < / button> < / div> < div className= "banner" > < h2> 輪播圖數據< / h2> < ul> { banners. map ( ( item, index ) => { return < li key= { index} > { item. title} < / li> } ) } < / ul> < / div> < div className= 'recommend' > < h2> 推薦數據< / h2> < ul> { recommends. map ( ( item, index ) => { return < li key= { index} > { item. title} < / li> } ) } < / ul> < / div> < / div> ) }
} ` * connect是一個函數,而且,connect的返回值,是一個高階函數(高階函數,接收一個組件作為參數)所以,這個 connect 是這樣使用的:connect(fn1, fn2)(about)* fn1函數,會接收一個state【就是store中的state (完整的 Redux state 樹)】,作用:將 Redux store 的 state 映射到組件的 props。* fn2函數,會接收一個dispatch((就是store中的dispatch))作用:將 Redux 的 dispatch 方法映射到組件的 props。export default connect(fn1)(fn2)(About) 這樣操作之后,就在 About組件中,使用 const { counter } = this.props,即可拿到store的state的counter屬性了也可以調用this.props.addNumber(1)、this.props.subNumber(2)* 這個 fn1 是隨便寫的,一般都用 mapStateToProps* 這個 fn2 是隨便寫的,一般都用 mapDispatcchToProps
`
function fn1 ( state ) { return { counter: state. counter, ` 說明,About組件,會使用store的state的counter屬性, ` ` xxx: state.xxx 說明,About組件,會使用store的state的xxx屬性, ` ` 總之,About組件,使用啥,就在這里列出來即可 ` banners: state. banners, recommends: state. recommends}
}
const mapStateToProps = state => ( { counter: state. counter } ) function fn2 ( dispatch ) { ` 這里 return 的對象的屬性,也會被合并到props中 ` return { addNumber ( num ) { dispatch ( addNumberAction ( num) ) } , subNumber ( num ) { dispatch ( subNumberAction ( num) ) } }
}
const mapDispatcchToProps = dispatch => ( { addNumber : num => dispatch ( addNumberAction ( num) ) , subNumber : num => dispatch ( subNumberAction ( num) )
} ) export default connect ( fn1, fn2) ( About)
connect 的工作流程
/*** connect 的工作流程* 1、訂閱Store:connect 會讓組件訂閱 Redux store 的變化* 2、注入Props:mapStateToProps 將需要的 state 片段注入到組件的 propsmapDispatchToProps 將 action 分發函數注入到組件的 props。* 3、自動更新:當 Redux store 的 state 變化時,mapStateToProps 會重新執行,如果返回的數據變化,組件會重新渲染* 4、觸發 Action:組件通過 this.props.addNumber() 等方法調用 mapDispatchToProps 返回的函數,觸發 Redux action 更新全局狀態*/