React18中react-redux使用,组件中异步操作,dispatch(function)-redux-thunk使用,combineReducers函数

894 阅读3分钟

react-redux使用

npm i react-redux 让 store 和 页面组件 产生关联

基本使用

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);
import * as actionTypes from "./constants";
export function addCountAction(count) {
  return {
    type: actionTypes.ADD_COUNT,
    count,
  };
}
export const subCountAction = (count) => ({
  type: actionTypes.SUB_COUNT,
  count,
});
import * as actionTypes from "./constants";
const initState = {
  count: 666,
};
function reducer(state = initState, action) {
  switch (action.type) {
    case actionTypes.ADD_COUNT:
      return { ...state, count: state.count + action.count };
    case actionTypes.SUB_COUNT:
      return { ...state, count: state.count - action.count };
    default:
      return state;
  }
}
export default reducer;
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addCountAction, subCountAction } from "../store/actionCreators";
export class About extends PureComponent {
  render() {
    const { count } = this.props;
    return (
      <div>
        <h2>About Page:{count}</h2>
        <div>
          <button onClick={(e) => this.props.addCount(6)}>+6</button>
          <button onClick={(e) => this.props.subCount(6)}>-6</button>
          <button onClick={(e) => this.props.addCount(10)}>+10</button>
          <button onClick={(e) => this.props.subCount(10)}>-10</button>
        </div>
      </div>
    );
  }
}
const mapStateToProps = (state) => ({ count: state.count });
const mapDispatchToProps = (dispatch) => ({
  addCount: (num) => dispatch(addCountAction(num)),
  subCount: (num) => dispatch(subCountAction(num)),
});
// connect返回值是一个高阶组件
export default connect(mapStateToProps, mapDispatchToProps)(About);
// <About {...this.props}  {...obj} />

组件中异步操作

npm i axios

image.png

代码:

import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { changeBannersAction, changeRecommendsAction } from "../store/actionCreators";
import axios from "axios";
export class Category extends PureComponent {
  componentDidMount() {
    axios.get("http://123.207.32.32:8000/home/multidata").then((res) => {
      const { banner, recommend } = res.data.data;
      const banners = banner.list;
      const recommends = recommend.list;
      //   console.log(banners, recommends);
      this.props.changeBanners(banners);
      this.props.changeRecommends(recommends);
    });
  }
  render() {
    return (
      <div>
        <h2>Category</h2>
      </div>
    );
  }
}
const mapDispatchToProps = (dispatch) => ({
  changeBanners: (banners) => dispatch(changeBannersAction(banners)),
  changeRecommends: (recommends) => dispatch(changeRecommendsAction(recommends)),
});
export default connect(null, mapDispatchToProps)(Category);

Category请求数据,存储到redux,About组件展示数据(mapStateToProps)

import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { addCountAction, subCountAction } from "../store/actionCreators";
export class About extends PureComponent {
  render() {
    const { count, banners, recommends } = this.props;
    return (
      <div>
        <h2>About Page:{count}</h2>
        <div>
          <button onClick={(e) => this.props.addCount(6)}>+6</button>
          <button onClick={(e) => this.props.subCount(6)}>-6</button>
          <button onClick={(e) => this.props.addCount(10)}>+10</button>
          <button onClick={(e) => this.props.subCount(10)}>-10</button>
        </div>
        <div>
          <h2>轮播图数据</h2>
          <ul>
            {banners.map((item, index) => {
              return <li key={index}>{item.title}</li>;
            })}
          </ul>
          <h2>推荐数据</h2>
          <ul>
            {recommends.map((item, index) => {
              return <li key={index}>{item.title}</li>;
            })}
          </ul>
        </div>
      </div>
    );
  }
}
const mapStateToProps = (state) => ({ count: state.count, banners: state.banners, recommends: state.recommends });
const mapDispatchToProps = (dispatch) => ({
  addCount: (num) => dispatch(addCountAction(num)),
  subCount: (num) => dispatch(subCountAction(num)),
});
// connect返回值是一个高阶组件
export default connect(mapStateToProps, mapDispatchToProps)(About);
// <About {...this.props}  {...obj} />
import * as actionTypes from "./constants";
export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners,
});
export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends,
});
export const CHANGE_BANNERS = "change_banners";
export const CHANGE_RECOMMENDS = "change_recommends";
import * as actionTypes from "./constants";
const initState = {
  count: 666,
  banners: [],
  recommends: [],
};
function reducer(state = initState, action) {
  switch (action.type) {
    case actionTypes.ADD_COUNT:
      return { ...state, count: state.count + action.count };
    case actionTypes.SUB_COUNT:
      return { ...state, count: state.count - action.count };
    case actionTypes.CHANGE_BANNERS:
      return { ...state, banners: action.banners };
    case actionTypes.CHANGE_RECOMMENDS:
      return { ...state, recommends: action.recommends };
    default:
      return state;
  }
}
export default reducer;
import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";
import { Provider } from "react-redux";
import store from "./store";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  // <React.StrictMode>
  <Provider store={store}>
    <App />
  </Provider>
  // </React.StrictMode>
);

image.png

理解中间件

image.png

dispatch(function)-redux-thunk使用

npm i redux-thunk

image.png

import { createStore, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
// 正常情况下 store.dispatch(object)
// 想派发函数 store.dispatch(function)使用中间件
const store = createStore(reducer, applyMiddleware(thunk));
export default store;
                                        Category.jsx
import React, { PureComponent } from "react";
import { connect } from "react-redux";
import { fetchDataAction } from "../store/actionCreators";
export class Category extends PureComponent {
  componentDidMount() {
    this.props.fetchData();
  }
  render() {
    return (
      <div>
        <h2>Category</h2>
      </div>
    );
  }
}
const mapDispatchToProps = (dispatch) => ({
  fetchData: () => dispatch(fetchDataAction()),
});
export default connect(null, mapDispatchToProps)(Category);
                                        actionCreators.js
import * as actionTypes from "./constants";
import axios from "axios";
export const changeBannersAction = (banners) => ({
  type: actionTypes.CHANGE_BANNERS,
  banners,
});
export const changeRecommendsAction = (recommends) => ({
  type: actionTypes.CHANGE_RECOMMENDS,
  recommends,
});
export const fetchDataAction = () => {
  // 如果是一个普通的action,需要返回action对象
  // 问题:对象中是不能直接拿到从服务器请求的异步数据的
  // return {} 如果返回一个函数,那么redux是不支持的,可以使用redux-thunk解决
  return (dispatch) => {
    // 异步操作:网络请求
    axios.get("http://123.207.32.32:8000/home/multidata").then((res) => {
      const { banner, recommend } = res.data.data;
      const banners = banner.list;
      const recommends = recommend.list;
      dispatch(changeBannersAction(banners));
      dispatch(changeRecommendsAction(recommends));
    });
  };
};

redux-devtools

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;

import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducer from "./reducer";
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;

// 正常情况下 store.dispatch(object)
// 想派发函数 store.dispatch(function)使用中间件
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
export default store;

image.png

image.png

Reducer文件拆分

image.png

image.png

combineReducers函数

image.png

自己实现:

image.png

image.png

完整拆分代码:

import { createStore, applyMiddleware, compose, combineReducers } from "redux";
import thunk from "redux-thunk";
// import reducer from "./reducer";
import countReducer from "./count";
import homeReducer from "./home";
import userReducer from "./user";
// 将多个reducer合并在一起
const reducer = combineReducers({
  count: countReducer,
  home: homeReducer,
  user: userReducer,
});
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({ trace: true }) || compose;
// 正常情况下 store.dispatch(object)
// 想派发函数 store.dispatch(function)使用中间件
const store = createStore(reducer, composeEnhancers(applyMiddleware(thunk)));
export default store;
                                                count文件夹
                                 actionCreators.js               
import * as actionTypes from "./constants";
export function addCountAction(count) {
  return {
    type: actionTypes.ADD_COUNT,
    count,
  };
}
export const subCountAction = (count) => ({
  type: actionTypes.SUB_COUNT,
  count,
});

                                 constants.js  
export const ADD_COUNT = "add_count";
export const SUB_COUNT = "sub_count";

                                 index.js
import reducer from "./reducer";
export default reducer;
export * from "./actionCreators";


                                 reducer.js
import * as actionTypes from "./constants";
const initState = {
  count: 666,
};
function reducer(state = initState, action) {
  switch (action.type) {
    case actionTypes.ADD_COUNT:
      return { ...state, count: state.count + action.count };
    case actionTypes.SUB_COUNT:
      return { ...state, count: state.count - action.count };
    default:
      return state;
  }
}
export default reducer;

image.png

在页面组件使用 store.getState().count.count

import React, { PureComponent } from "react";
import store from "../store";
import { addCountAction } from "../store/count/actionCreators";

export class Home extends PureComponent {
  constructor() {
    super();
    this.state = {
      count: store.getState().count.count,
    };
  }
  componentDidMount() {
    store.subscribe(() => {
      const state = store.getState().count;
      console.log("Home subscribe state=> ", state);
      this.setState({
        count: state.count,
      });
    });
  }
  addCount(num) {
    store.dispatch(addCountAction(num));
  }
  render() {
    const { count } = this.state;
    return (
      <div>
        <h2>Home count:{count}</h2>
        <div>
          <button onClick={(e) => this.addCount(1)}>+1</button>
          <button onClick={(e) => this.addCount(5)}>+5</button>
          <button onClick={(e) => this.addCount(10)}>+10</button>
        </div>
      </div>
    );
  }
}
export default Home;