表示在执行一个函数时,除了返回函数值之外,还对调用函数产生了附加的影响。比如修改了全局变量,修改参数或者改变了外部的存储
示例:
// store/index.js
import { createStore } from "redux"
import reducer from "./reducer"
const store = createStore(reducer)
export default store
// store/reducer.js
import * as actionTypes from "./contants"
const initialState = {
counter: 100
}
function reducer(state = initialState, 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 }
default: return state
}
}
export default reducer
// store/actionCreators.js
import * as actionTypes from "./contants"
export const addNumberAction = (num) => ({
type: actionTypes.ADD_NUMBER,
num
})
export const subNumberAction = (num) => ({
type: actionTypes.SUB_NUMBER,
num
})
// store/constants.js
export const ADD_NUMBER = "add_number"
export const SUB_NUMBER = "sub_number"
import store from '../store'
import { addNumberAction } from '../store/actionCreators'
export class Home extends PureComponent {
constructor() {
super()
this.state = {
counter: store.getState().counter
}
}
componentDidMount() {
store.subscribe(() => {
const state = store.getState()
this.setState({ counter: state.counter })
})
}
addNumber(num) {
store.dispatch(addNumberAction(num))
}
render() {
const { counter } = this.state
return (
{ counter }
)
}
}
npm install react-redux
// index.js
import { Provider } from 'react-redux'
import store from './store'
root.render(
)
// home.jsx
import { connect } from "react-redux"
export class Home extends PureComponent {
calcNumber(num, isAdd) {
if(isAdd) {
this.props.addNumber(num)
} else {
this.props.subNumber(num)
}
}
render() {
const { counter } = this.props
return (
{ counter }
)
}
}
// 当组件所依赖的store 中的数据发生变化时,组件会重新调用render 函数
// connect 的第一个参数:将store 中的state 中的数据,映射到props 中
const mapStateToProps = (state) => ({ counter: state.counter })
// connect 的第二个参数:将store 中的dispatch 中的action,映射到props 中
const mapDispatchToProps = (dispatch) => ({
addNumber: (num) => dispatch(addNumberAction(num));
subNumber: (num) => dispatch(subNumberAction(num));
})
// connect 本身是一个高阶函数,接收两个函数作为参数
// connect() 返回值是一个新函数,这个新函数是一个高阶组件,接收组件作为参数
export default connect( mapStateToProps, mapDispatchToProps )(Home)
// store/index.js
import { createStore, applyMiddleware } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"
const store = createStore(reducer, applyMiddleware(thunk))
export default store
// actionCreators.js
export const changeBannersAction = (banners) => {
type: actionTypes.CHANGE_BANNERS,
banners
}
export const fetchHomeMultidataAction = () => {
return function(dispatch, getState) {
axios.get("http://").then(res => {
const banners = res.data.data.banner.list
// dispatch({ type: actionTypes.CHANGE_BANNERS, banners })
dispatch(changeBannersAction(banners))
})
}
}
// banners.jsx
import { connect } from "react-redux"
import { fetchHomeMultidataAction } from "../store/actionCreators.js"
export class Banners extends PureComponent {
componentDidMount() {
this.props.fetchHomeMultidata()
}
render() {
return (
{ this.props.counter }
)
}
}
const mapStateToProps = (state) => {
counter: state.counter
}
const mapDispatchToProps = (dispatch) => {
fetchHomeMultidata() {
dispatch(fetchHomeMultidataAction())
}
}
export default connect( mapStateToProps, mapDispatchToProps )(Banners)
// combineReducers 的实现原理
function reducer( state = {}, action ) {
return {
counter: counterReducer(state.counter, action),
home: homeReducer(state.home, action)
}
}
// store/index.js
import { combineReducers } from "redux"
import counterReducer from './counter/index.js'
import homeReducerfrom './home'
// 将多个reducer 合并在一起
const reducer = combineReducers({
counter: counterReducer,
home: homeReducer
})
const store = createStore(reducer, applyMiddeware(thunk))
export default store
// home.jsx
constructor() {
super()
counter: store.getState().counter.counter
}
// store/index.js
impoort { configureStore } from '@reduxjs/toolkit'
import counterReducer from './features/counter'
const store = configureStore({
reducer: {
counter: counterReducer
}
})
export default store
// store/features/counter.js
impoort { createSlice } from '@reduxjs/toolkit'
const counterSlice = createSlice({
name: "counter",
initialState: {
counter: 100
}
reducers: {
addNumber(state, action) {
const paylaod = action.payload
state.counter = state.counter + payload
},
subNumber(state, { payload }) {
const paylaod = action.payload
state.counter = state.counter - payload
}
}
})
export const { addNumber, subNumber } = counterSlice.actions
export default counterSlice.reducer
// src/index.js
import { Provider } from 'react-redux'
import App from './App'
import store from './store'
const root = ReactDom.createRoot(document.getElementById('root'))
root.render(
)
// src/App.jsx
import { connect } from "react-redux"
import { subNumber } from '../store/features/counter'
export class App extends PureComponent {
addNumber(num) {
this.props.addNumber(num)
}
subNumber(num) {
this.props.subNumber(num)
}
render() {
const { counter } = this.props
return (
counter: { counter }
)
}
}
const mapStateToProps = (state) => {
counter: state.counter.counter
}
const mapDispatchToProps = (dispatch) => {
addNumber(num) {
dispatch(addNumber(num))
}
subNumber(num) {
dispatch(subNumber(num))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(App)
// store/features/home.js
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit'
export const fetchHomeMultidataAction = createAsyncThunk("fetchhomedata", async () => {
const res = await axios.get("http")
return res.data
})
// fetchHomeMultidataAction 的另一种写法
// export const fetchHomeMultidataAction = createAsyncThunk("fetchhomedata", async (extraParams, { dispatch, getState }) => {
// const res = await axios.get("http")
// const banners = res.data.data.banner.list
// dispatch(changeBanners(banners))
// })
const homeSlice = createSlice({
name: "home",
initialState: {
banners: [],
},
reducers: {
changeBanners(state, { payload }) {
state.banners = payload
},
},
extraReducers: {
[fetchHomeMultidataAction.pending](state, action) {
console.log("异步操作的pending 状态")
},
[fetchHomeMultidataAction.fulfilled](state, { payload }) {
state.banners = payload.data.banner.list
},
[fetchHomeMultidataAction.rejected](state, action) {
console.log("异步操作的rejected 状态")
}
},
// extraReducers 的函数写法
// extraReducers: (builder) => {
// builder.addCase(fetchHomeMultidataAction.pending, (state, action) => {
// console.log("异步操作的pending 状态")
// }).addCase(fetchHomeMultidataAction.fulfilled, (state, { payload }) => {
// state.banners = payload.data.banner.list
// }).addCase(fetchHomeMultidataAction.rejected, (state, action) => {
// console.log("异步操作的rejected 状态")
// })
// }
})
export const { changeBanners } = homeSlice.actions
export default homeSlice.reducer
// src/Home.jsx
export class Home extends PureComponent {
componentDisMount() {
this.props.fetchHomeMultidata()
}
}
const mapDispatchToProps = (dispatch) => {
fetchHomeMultidata() {
dispatch(fetchHomeMultidataAction())
}
}
export default connect(mapDispatchToProps)(Home)
import { PureComponent } from 'react'
import store from "../store"
export default function connect(mapStateToProps, mapDispatchToProps) {
return function(WrapperComponent) {
constructor(props) {
super(props)
this.state = mapStateToProps(store.getState())
}
componentDidMount() {
this.unsubscribe = store.subscribe(() => {
this.setState(mapStateToProps(store.getState()))
})
}
componentWillUnmount() {
this.unsubscribe()
}
render() {
const stateObj = mapStateToProps(store.getState())
const dispatchObj = mapDispatchToProps(store.dispatch)
return
}
}
return NewComponent
}
function patchLogging(store) {
let next = store.dispatch
function dispatchAndLog(action) {
console.log("dispatching:", action)
next(addAction(5))
console.log("新的state:", store.getState())
}
store.dispatch = dispatchAndLog;
}
function thunk(store) {
const next = store.dispatch
function dispatchThunk(action) {
if(typeof action === "function"){
action(store.dispatch, store.getState)
} else {
next(action)
}
}
store.dispatch = dispatchThunk
}
thunk(store)
function applyMiddleware(store, ...fns) {
fns.forEach(fn => {
fn(store)
})
}
export default appliMiddleware