Redux使用

Reduxopen in new window 是 JavaScript 状态容器,提供可预测化的状态管理。

An image

1. 安装redux

安装redux

npm install --save redux

多数情况下,你还需要使用 React 绑定库和开发者工具。

npm install --save react-redux
npm install --save-dev redux-devtools

react原理图

2. redux示例

redux目录结构(react-redux-demo示例)open in new window

        |-- .gitignore
        |-- package.json
        |-- README.md
        |-- yarn.lock
        |-- public
        |   |-- favicon.ico
        |   |-- index.html
        |   |-- logo192.png
        |   |-- logo512.png
        |   |-- manifest.json
        |   |-- robots.txt
        |-- src
            |-- App.css
            |-- App.js
            |-- index.css
            |-- index.js
            |-- logo.svg
            |-- reportWebVitals.js
            |-- setupTests.js
            |-- components
            |   |-- Count.jsx
            |   |-- Products.jsx
            |-- redux
                |-- store.js
                |-- actions
                |   |-- count.js
                |   |-- products.js
                |-- reducers
                    |-- count.js
                    |-- index.js
                    |-- products.js

2.1 index.js引入redux

使用Provider store={store}外层包裹App
src/index.js

import { Provider } from 'react-redux';
import store from './redux/store';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <App />
    </Provider>
  </React.StrictMode>
);

2.2 定义store

src/redux/store.js

import { createStore, applyMiddleware } from 'redux';
import { combineReducers } from 'redux';
import rootReducer from './reducers';
import thunk from 'redux-thunk'
import { composeWithDevTools } from 'redux-devtools-extension';

export default createStore(combineReducers(rootReducer),
  composeWithDevTools(applyMiddleware(thunk)))

2.3 定义actions

分别定义了两个action,productsAction,countAction,然后进行合并

定义countAction

src/actions/count.js


export const INCREMENT = 'INCREMENT COUNT';
export const increment = data => ({ type: INCREMENT, data })

export const incrementAsync = data => dispatch => {
  setTimeout(() => {
    dispatch(increment(data))
  }, 2000)
}

定义productsAction

src/actions/products.js

export const ADD_PRODUCT = 'ADD PRODUCT';
export function addProduct(data) {
  return {
    type: ADD_PRODUCT,
    data
  }
}

2.4 定义Reducer

定义rootReducer

src/reducers/index.js
分别定义了两个Reducer,productsReducer,countReducer,然后进行合并

import productsReducer from './products';
import countReducer from './count';

const rootReducer = {
  products: productsReducer,
  count: countReducer
}

export default rootReducer;

定义productsReducer

src/reducers/products.js

import { ADD_PRODUCT } from '../actions/products';
const initState = [];
const productsReducer = (state = initState, action) => {
  const { data, type } = action;
  switch (type) {

    case ADD_PRODUCT:
      return [data, ...state];

    default:
      return state;
  }
}

export default productsReducer;

定义countReducer

src/reducers/countReducer.js

import { INCREMENT } from '../actions/count';
const initState = 0;
const countReducer = (state = initState, action) => {

  const { data, type } = action;
  switch (type) {

    case INCREMENT:
      return state + data;

    default:
      return state;
  }
}

export default countReducer;

目前reducer与actions已经定义完毕

2.5 组件中使用redux

使用connect连接react-redux与组件 An image

import { connect } from "react-redux";
 
 /*  
    connect柯里化函数:
    一阶参数中传入(mapStateToProps,mapDispatchToProps)
    mapStateToProps映射store中的state到组件的props  
*/
connect(mapStateToProps, mapDispatchToProps)(Count)

/*
  通过store中的state取值state.count,state.products分别来自于rootReducer
  对两个模块的定义
  const rootReducer = {
    products: productsReducer,
    count: countReducer
  }
*/
const mapStateToProps=(state) => ({
   count: state.count,
   products: state.products,
});

/*
mapDispatchToProps映射store中的dispatch到组件的props
increment, incrementAsync分别为src/redux/actions/count的actions   

二阶参数传入组件(Count)   
*/
const mapDispatchToProps = { increment, incrementAsync };

count组建中使用redux

src/components/count.jsx

import React from "react";
import { increment, incrementAsync } from "../redux/actions/count";
import { connect } from "react-redux";

const Count = (props) => {
  const addClick = () => {
    props.increment(1);
  };

  const addClickAsync = () => {
    props.incrementAsync(1);
  };

  return (
    <div>
      <button onClick={addClick}>count+1</button>
      <button onClick={addClickAsync}>countAsync+1</button>
      <div>count: {props.count}</div>
      <div>productsLength:{props.products.length}</div>
    </div>
  );
};

const mapStateToProps = (state) => ({
  count: state.count,
  products: state.products,
});
const mapDispatchToProps = { increment, incrementAsync };

export default connect(mapStateToProps, mapDispatchToProps)(Count);

Products组建中使用redux

src/components/Products.jsx

import React from "react";
import { connect } from "react-redux";
import { addProduct } from "../redux/actions/products";

function Products(props) {
  const addProductsClick = () => {
    props.addProduct({ id: Date.now(), name: Date.now() });
  };

  return (
    <div>
      <button onClick={addProductsClick}>addProducts</button>
      <ul>
        {props.products.map((item) => (
          <li key={item.id}>{item.name}</li>
        ))}
      </ul>
    </div>
  );
}

const mapStateToProps = (state, next) => ({ products: state.products });
const mapDispatchToProps = { addProduct };

export default connect(mapStateToProps, mapDispatchToProps)(Products);

Contributors: masecho