Redux basic tutorial

Time:2022-6-11

@(blog)

Redux basic tutorial

The readers of this article are those who understand the concept of flux, are familiar with react, and understand ES6 grammar

reduxIt’s a hot one recentlyfluxFramework. In just one month, there are now 2900+ stars. After watch, hundreds of PR emails are received every day. There is no more nonsense.
Whyredux, see connectionThe Evolution of Flux Frameworks

main features

  • Everything (Stores, Action Creators, configuration) is hot reloadable. —— It should be very cool to cooperate with hotloader, although it is used nowbrowserifyThe benefits are not obvious.
  • storeThe data in is unlimited and can benumber object arrayWait, crap, because it’sstoreJust a simple function.
  • providedevtools, monitoringactionTriggering of andstateChanges in.
  • The source code is clear, simple and lightweight. There is no need for documentation. Just look at the source code directly The disadvantage is that if you don’t understand the source code, you won’t feel clear enough just looking at the documents.
  • apiIt’s very simple. You don’t have to remember a lotapi
  • every thing is simple function
  • connecterAndproviderThese two things are always cumbersome and not so elegant.

The following is an example of a simple counterreduxThe core method and some points needing attention.

  • Synchronous and asynchronous actioncreators
  • Use of Middleware
  • dispatch actions
  • Get and synchronize state

Code placed inhttps://github.com/yeatszhang/redux-tutorial, gulp needs to be installed

Code is branch basedv1.0.0-rcAPI is slightly different. SeeBreaking API changes for 1.0

actionCreator

Actions creator is a function used to generate actions. By default, it can accept returnsobjectperhapsfunctionWhen learning flux, many people confuse action with actioncreator

//Return object directly
actionCreators.addTodo = function(text) {
  return {
    type: types.ADD_TODO,
    text
  };
}

//Return function
actionCreators.incrementAsync = function() {
  return (dispatch, getState) => {
    //In actioncreator, you can get the current state through getstate
    console.log(getState());
    //Asynchronous action
    setTimeout(() => {
      dispatch({
        type: INCREMENT_COUNTER2,
      });
    }, 1000);
  };
};

Without using anymiddlewareIn this case, there are only twoactionCan bedispatch

app

In the outermost layer of dynamic content, the provider should be used for wrapping. The provider receives the store as a parameter. Note that children is afunctionNot at allreactElement
providerPass the store to the child node as a context, and implementstoreHot swap for. Therefore, components in the provider can actually get the dispatch and state through the context instead of connect. However, the author does not recommend this.

import React from 'react';
import { createStore, applyMiddleware, combineReducers } from 'redux';
// redux midlleware repositories
import thunk from 'redux-thunk';
//Extract the Redux and react related parts, such as the connector provider, separately
import { Provider } from 'react-redux';
import reducers from '../reducers';
import CounterApp from './CounterApp.js';
import logMiddleware from '../middleWares/logMiddleware.js';

const reducer = combineReducers(reducers);
const createStoreWithMiddleware = applyMiddleware(thunk, logMiddleware)(createStore);
const store = createStoreWithMiddleware(reducer);
//Using middleware thunk, you can write directly if there is no requirement to customize the m-server
// const store = createStore(reducer);

class App extends React.Component {
  render() {
    return (
      <Provider store={store}>
        {() => <CounterApp />}
      </Provider>
    );
  }
}

smart component

Smart component has two characteristics:

  1. Automatically associate the states in the store and re render automatically
  2. Events can be distributed through dispatch to trigger the update of the store

Students who have just come into contact with Redux will certainly find this connect very difficult to understand. Or say in the code…

/**
 * Created by yichizhang on 15/7/26.
 */

import React, { Component } from 'react';
import { bindActionCreators } from 'redux';
import { Connector } from 'react-redux';
import Counter from '../components/Counter';
import actionCreators1 from '../actionCreators/actionCreators1.js';
import actionCreators2 from '../actionCreators/actionCreators2.js';

//State is the set of states in each reducer
function select(state) {
  //Select the state that the component needs to listen to from each reducer
  return {
    counter1: state.reducer1.counter,
    counter2: state.reducer2.counter,
  };
}

export default class CounterApp extends Component {
  //The return value of the select function and an object of the dispatch assembly process are used as parameters
  //From here, we can see that the connector is to help get the dispatch method of the store in the provider and select the state to be used
  renderChild({ counter1, counter2, dispatch}) {
    //Personally, I find it inconvenient to use actions in this way, especially when the component only needs to trigger actions and does not need to listen to changes in the store. I will be lazy to get the dispatch through the context~~
    const actions1 = bindActionCreators(actionCreators1, dispatch);
    const actions2 = bindActionCreators(actionCreators2, dispatch);
    const props = { ...actions1, ...actions2, counter1, counter2 };
    //All actions and states will be provided to the counter in the form of props, and then you can do whatever you want in the counter~
    return <Counter {...props} />;
  }

  render() {
    return (
      <Connector select={select}>
        {this.renderChild}
      </Connector>
    );
  }
}

reducer

Redux thinks that programmers do not need to write the logic in the store, but only need to write the processing logic for the state:

old  sate => action  => new state

This is a fully synchronized process. The reducer only needs to declare the initial state and the change rules of the state after receiving the action.

import React from 'react/addons';
import {INCREMENT_COUNTER1, DECREMENT_COUNTER1} from '../constants/actionsTypes.js';
const update = React.addons.update;

//State can be any type
const initialState = {
  counter: 0,
};

//Reducer is just a simple switch method
export default function counter(state = initialState, action = null) {
  switch (action.type) {
    case INCREMENT_COUNTER1:
      //It should be noted that the connector will perform a "share equal" operation when the state in the select changes,
      //Therefore, if you need to operate the reference value, you must not directly assign a value. You need to use update or immutable in addon JS, I know that I don't want to continue learning these two tools It's simple
      //This can greatly avoid repeated render and improve performance
      return update(state, {
        counter: {
          $set: state.counter + 1,
        },
      });
    case DECREMENT_COUNTER1:
      return update(state, {
        counter: {
          $set: state.counter - 1,
        },
      });
    default:
      return state;
  }
}

middleWare

Interested students can have a look. Generally speaking, the default thunk is enough. I added an intermediate layer of log to the example

//Print triggered action
function logMiddleware() {
  //Next here is the next Middleware
  return function(next) {
    return function(action) {
      //Print this action and process it with the next Middleware
      console.log(action);
      next(action);
    };
  };
}

export default logMiddleware;

//The following is the default thunk Middleware

function thunkMiddleware(_ref) {
  var dispatch = _ref.dispatch;
  var getState = _ref.getState;

  return function (next) {
    return function (action) {
      //If it is a function, execute the function with dispatch and getstate as parameters. Otherwise, write a middleware for processing
      return typeof action === 'function' ? action(dispatch, getState) : next(action);
    };
  };
}

epilogue

In fact, where Redux doesn’t understand, it’s better to directly look at the source code. The amount of code in Redux is very small and the organization is very clear. It is recommended that everyone should look at it. However, the author seems to have a heavy mind on functional programming, using a lot of modifier syntax, and reducing~ is very convoluted~

After that, I will summarize my experience in reading the Redux source code and the implementation principle of each functional module~