Redux from scratch

What is Redux

Redux is a JavaScript state container that provides predictable state management. At present, it is generally used with react. React provides a react Redux library, which can be easily combined.

What you need to know before you start

Why do you need state management?

  • Passing props down many times is too cumbersome
  • The same api may request multiple times in different situations

If you have Vuex development experience, you will get started quickly.

Easy to use

In Redux, the state is changed through action, which actually calls the reducer method. An action can tell the reducer what the next action (type) is and how to change the data.

Compared with Vuex, in Vuex, we commit a state change through action. In Redux, action calls reducer.

First, let's create a new store.

js

1// src/store/index.js
2import { createStore } from 'redux';
3
4import reducer from './reducers';
5export default createStore(reducer);

COPY

To create a new store, you need to pass in a reducer. Here, let's write a small example. state records a data and changes its size through action.

js

1import T from '../actions/types';
2// import { add } from '../actions';
3import { combineReducers } from 'redux';
4
5const initState = {
6  num: 1
7};
8
9const change = (state = initState, action) => {
10  const { type, num } = action;
11  console.log(num);
12
13  switch (type) {
14    case T.ADD:
15      return {
16        num: ++state.num
17      };
18    case T.REDUCE:
19      return {
20        num: --state.num
21      };
22    default:
23      return state;
24  }
25};
26
27export default combineReducers({
28  change
29});

COPY

As mentioned earlier, action calls reducer, so we need an action.

js

1import T from './types';
2
3export function add(num) {
4  return {
5    type: T.ADD,
6    num
7  };
8}
9export function reduce(num) {
10  return {
11    type: T.REDUCE,
12    num
13  };
14}

COPY

js

1// store/actions/types.js
2export const types = Object.freeze({
3  ADD: 'ADD',
4  REDUCE: 'REDUCE'
5});
6
7export default types;

COPY

An action consists of a type and a payload. Type tells the reducer which update method to adopt.

Let's take a look at what reducer consists of.

js

1// src/store/reducers/index.js
2import T from '../actions/types'; // Generally, actionTypes can be uniformly recorded in one file
3import { combineReducers } from 'redux';
4
5const initState = {   // Original states
6  num: 1
7};
8
9// ADD variable name as key in getStates
10const change = (state = initState, action) => {
11  // State does not exist by default, so you need to make a default value, that is, initialization. After initialization, each call will pass in the state that has not been updated
12  // action records the type, payload, and here is num
13  const { type, num } = action;
14
15  switch (type) {
16      // Judge the type and change the data. A new state should be returned. Note: it must be a new object, not a reference
17
18    case T.ADD:
19      return {
20        num: state.num + num
21      };
22		case T.REDUCE:
23      return {
24        num: --state.num
25      };
26    default:
27      // Mismatched action types, returned directly.
28      // An action will be received by multiple reducer s. Pay attention to type listening.
29      return state;
30  }
31};
32
33// Use combineReducers to connect multiple reducers, although there is only one here
34export default combineReducers({
35  change
36});

COPY

At this point, a store that stores numbers and can change its size through action is written. Then we use it in react.

js

1// app.js
2
3import store from './store';
4ReactDOM.render(
5    <App {...store} />,
6  document.getElementById('root')
7);

COPY

Mount the store instance to the root component, and the next layer component can receive it through props.

Through the getState method, we can get the value stored in the store. For example, I want to get the state in the change reducer.

console.log(this.props.getState().change);

You can also modify the value of state through the dispatch method. this.props.dispatch(add(1))

Here, redux is basically getting started. Next, it is bound with React. I don't know if you noticed that you can only pass one layer of parameters from the root component, which violates the principle of using store anytime, anywhere. Then React redux appeared.

React Redux provides a high-level component of the Provider, passes in a store, and then uses it in all sub components of the lower layer. You can get the store by using the connect method.

js

1import store from './store';
2import { Provider } from 'react-redux';
3ReactDOM.render(
4  <Provider store={store}>
5    <App />
6  </Provider>,
7  document.getElementById('root')
8);

COPY

Instead of exporting a default Component in the subcomponent, a connect Component is exported.

js

1import React, { Component } from 'react';
2import { connect } from 'react-redux';
3import { add, reduce } from '../store/actions';
4import styles from './style.module.css';
5class Demo extends Component {
6  render() {
7    console.log(this.props);
8
9    return (
10      <div className={styles['wrap']}>
11        <button onClick={() => this.props.add(1)}>+</button>
12        <span style={{ color: '#fff' }}>{this.props.num}</span>
13        <button onClick={() => this.props.reduce(1)}>-</button>
14      </div>
15    );
16  }
17}
18const mapStateToProps = state => {
19  return {
20    num: state.change.num
21  };
22};
23const mapDispatchToProps = dispatch => {
24  return {
25    add: num => dispatch(add(num)),
26    reduce: num => dispatch(reduce(num))
27  };
28};
29
30export default connect(mapStateToProps, mapDispatchToProps)(Demo);

COPY

mapStateToProps is a bit like mapGetter. mapStateToProps receives a state and returns an object, which will be directly mounted on props.

mapDispatchToProps is like mapActions. It returns an object, which will also be directly mounted on props. The function in this object returns a function that can receive parameters and call dispatch to change state.

Added by Ascendancy on Tue, 04 Jan 2022 06:53:40 +0200