纯函数要符合以下两个特点:
整个应用程序的state只存储在一个 store 中,创建多个Store,不利于数据的维护,单一的数据源可以让整个应用程序的state变得方便维护、追踪、修改。
提供方:
const { createStore } = require("redux");
// 创建一个对象,保存的状态
const initialState = {
name: "why",
counter: 100,
};
// 创建Store来存储这个state,创建store时必须创建reducer
function reducer(state = initialState, action) { // 初始值
return state;
}
// 创建的store
const store = createStore(reducer); // reducer的返回值
module.exports = store;
使用方:
const store = require("./store")
console.log(store.getState()) // { name: 'why', counter: 100 }
2. 修改 store 中的数据
使用方修改数据:
// 通过action来修改state,通过dispatch来派发action
const nameAction = { type: "change_name", name: "kobe" }; // action
store.dispatch(nameAction); // 执行 reducer 函数
// 获取修改之后的 state
console.log(store.getState()); // { name: 'kobe', counter: 100 }
提供者处理:
const { createStore } = require("redux");
// 初始化的数据
const initialState = {
name: "why",
counter: 100,
};
// 在这里处理
function reducer(state = initialState, action) {
switch (action.type) {
case "change_name":
return { ...state, name: action.name }; // 不需要直接修改state
case "add_number":
return { ...state, counter: state.counter + action.num };
default:
return state;
}
}
// 创建的store
const store = createStore(reducer);
module.exports = store;
3. 订阅 store 中的数据,store 中的数据改变之后打印
使用方:
const unsubscribe = store.subscribe(() => {
console.log("订阅数据的变化:", store.getState())
})
// 修改 state 中的数据时
store.dispatch({ type: "change_name", name: "kobe" }) // 订阅数据的变化: { name: 'kobe', counter: 100 }
const { createStore } = require("redux");
const reducer = require("./reducer.js");
// 创建的store
const store = createStore(reducer);
module.exports = store;
store/reducer.js
const { ADD_NUMBER, CHANGE_NAME } = require("./constants")
// 初始化的数据
const initialState = {
name: "why",
counter: 100
}
function reducer(state = initialState, action) {
switch(action.type) {
case CHANGE_NAME:
return { ...state, name: action.name }
case ADD_NUMBER:
return { ...state, counter: state.counter + action.num }
default:
return state
}
}
module.exports = reducer
store/constants.js
const ADD_NUMBER = "add_number"
const CHANGE_NAME = "change_name"
module.exports = {
ADD_NUMBER,
CHANGE_NAME
}
store/actionCreators.js
const { ADD_NUMBER, CHANGE_NAME } = require("./constants")
const changeNameAction = (name) => ({
type: CHANGE_NAME,
name
})
const addNumberAction = (num) => ({
type: ADD_NUMBER,
num
})
module.exports = {
changeNameAction,
addNumberAction
}
使用方:
// 使用 actionCreators 中函数返回的 action 对象
const store = require("./store");
const { addNumberAction, changeNameAction } = require("./store/actionCreators");
store.dispatch(changeNameAction("kobe"));
store.dispatch(changeNameAction("lilei"));
代码:
home.jsx
import React, { PureComponent } from 'react'
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 (
Home Counter: {counter}
)
}
}
export default Home
import React, { PureComponent } from 'react'
import store from "../store"
import { subNumberAction } from '../store/actionCreators'
export class Profile extends PureComponent {
constructor() {
super()
this.state = {
counter: store.getState().counter
}
}
componentDidMount() {
store.subscribe(() => {
const state = store.getState()
this.setState({ counter: state.counter })
})
}
subNumber(num) {
store.dispatch(subNumberAction(num))
}
render() {
const { counter } = this.state
return (
Profile Counter: {counter}
)
}
}
export default Profile
store / actionCreators.js
import * as actionTypes from "./constants"
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"
store / reducer.js
import * as actionTypes from "./constants"
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 / index.js
import { createStore } from "redux"
import reducer from "./reducer"
const store = createStore(reducer)
export default store
功能:将 redux 和页面建立连接
1. 安装react-redux: yarn add react-redux
2. 在 index.js 文件中使用 store,所有的页面都可以使用 store 了
import App from './App';
import { Provider } from "react-redux"
import store from "./store"
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
);
3. 页面中使用 connect 高阶函数,connect 高阶函数是需要传两个参数的。
about.jsx:
mapStateToProps 映射 state
import React, { PureComponent } from 'react'
import { connect } from "react-redux"
export class About extends PureComponent {
render() {
// 2. 映射过来的数据在 props 中获取
const { counter, banners, recommends, userInfo } = this.props
}
}
// 1. 将 store 中的数据映射过来
const mapStateToProps = (state) => ({
counter: state.counter.counter,
banners: state.home.banners,
recommends: state.home.recommends,
userInfo: state.user.userInfo
})
export default connect(mapStateToProps)(About)
mapDispatchToProps 映射 action
页面中执行一个操作的时候,函数中是要调用 dispatch 函数,操作过多,应该要简化。
about.jsx
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addNumberAction, subNumberAction } from "../store/counter";
export class About extends PureComponent {
calcNumber(num, isAdd) {
if (isAdd) {
this.props.addNumber(num);
} else {
this.props.subNumber(num);
}
}
render() {
const { banners, userInfo } = this.props;
return (
nickname: {userInfo.nickname}
轮播图数据:
{banners.map((item, index) => {
return - {item.title}
;
})}
);
}
}
const mapStateToProps = (state) => ({
banners: state.home.banners,
userInfo: state.user.userInfo,
});
const mapDispatchToProps = (dispatch) => ({
addNumber(num) {
dispatch(addNumberAction(num));
},
subNumber(num) {
dispatch(subNumberAction(num));
},
});
export default connect(mapStateToProps, mapDispatchToProps)(About);
网络请求到的数据属于状态管理的一部分,也交给redux来管理。
dispatch 函数中需要传递一个对象,并且在 dispatch 是同步执行的,不能执行异步操作,需要将 dispatch 函数进行增强,在这里使用 redux-thunk 作为中间件增强 dispatch 函数。
import { createStore, applyMiddleware } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
export default store
3. 这时候可以定义返回值是函数的 action,这个函数在 dispatch 之后执行。
页面代码:
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 (
Category Page: {this.props.counter}
)
}
}
const mapStateToProps = (state) => ({
counter: state.counter
})
const mapDispatchToProps = (dispatch) => ({
fetchHomeMultidata() {
dispatch(fetchHomeMultidataAction()) // action 是函数类型
}
})
export default connect(mapStateToProps, mapDispatchToProps )(Category)
actionCreators.js
import axios from "axios";
export const changeBannersAction = (banners) => ({
type: actionTypes.CHANGE_BANNERS,
banners,
});
export const changeRecommendsAction = (recommends) => ({
type: actionTypes.CHANGE_RECOMMENDS,
recommends,
});
export const fetchHomeMultidataAction = () => { // 这里的 action 返回值是函数
return function (dispatch, getState) {
axios.get("http://123.207.32.32:8000/home/multidata").then((res) => {
const banners = res.data.data.banner.list;
const recommends = res.data.data.recommend.list;
// 回来数据之后,调用原来的action
dispatch(changeBannersAction(banners));
dispatch(changeRecommendsAction(recommends));
});
};
};
import { createStore, applyMiddleware, compose } from "redux"
import thunk from "redux-thunk"
import reducer from "./reducer"
// redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
export default store
import { createStore, applyMiddleware, compose, combineReducers } from "redux"
import thunk from "redux-thunk"
import counterReducer from "./counter"
import homeReducer from "./home"
import userReducer from "./user"
// 将两个reducer合并在一起
const reducer = combineReducers({
counter: counterReducer,
home: homeReducer,
user: userReducer
})
// redux-devtools
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({trace: true}) || compose;
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)))
export default store
页面中使用:
constructor() {
super()
this.state = {
counter: store.getState().counter.counter
}
}