• First of all, what is redux? Why redux? What does it solve?

It’s well known that if you want to learn about a technology, you should go to redux’s website.

  • You can see:

React is a JavaScript library for building user interfaces

Redux is a state container for JavaScript applications that provides predictable state management

So what is the relationship between the two? We know that although the React is actually a UI framework (not even a framework that is just a library), but its method is very chic, rendering UI through JSX generate dynamic vdom rendering UI, it different from the traditional way, it has no structure, no template, no routing, it has no design patterns, and data management, that is to say, React doesn’t do anything but render the UI.

However, for a large, complex site, design patterns and data management are necessary, so there’s no way to develop a large project using React alone. Here’s an example:

Take a look at the image on the left above. It represents the structure of our React component. Each node represents each component, and the green nodes represent the data that needs to be passed

Assuming that our website is through such a component tree form rendering of the UI, we know that in the react, the flow of data is unidirectional, and always top-down transfer, we can use props component data from components to the father, but, if we want to put the following green nodes of a data transfer to the top node, How do the different components communicate with each other at this point?

Follow the principle of the react, we have no way to transfer data directly, but we can through the way of function callback, by calling the parent component’s function, a layer of a layer of data transferred upwards, in fact, in large projects, such as the need to share data is very common, if we pass the callback function that way synchronous data layer, If you’re not careful, you can get stuck in an infinite loop, so for medium to large projects, you need design patterns.

As for design patterns, you probably know MVC, MVVM, MV*, etc… However, for React, we can also use an architectural mode that is more in line with React design idea, which is Redux. Redux is a design mode and an architectural scheme of the project. It does not depend on any library or framework. It can even be used in Vue or Angular. Of course, it is rarely used in Vue or Angular because both Vue and Angular have their own data frameworks (such as Vue’s Vuex, And Angular Observables.)

Look at the image on the right above. Again, it represents the structure of our React component. The difference is that none of the components communicate directly, and all data is stored in a repository called the Store.

  • Stripping component Data (Store)
  • Data is uniformly stored in stores
  • Component subscriptions get data
  • Store pushes data updates synchronously

That’s how Redux works

In a nutshell, Redux is a data warehouse that stores data in a unified way, isolating data from the UI while handling their binding relationships

So when do you need redux?

  • When components need to share data (or state)
  • When a state needs to be accessible from anywhere at any time
  • When one component needs to change the state of another component
  • Such as language switching, skin theme switching, user login status, login data sharing…

All in all, the purpose of redux is to make data manageable and predictable, but what would workflow look like in a real project? Take a look at the chart below:

In general, with redux, a repository is created to Store data, which is the Store in the figure above. In this Store, there is one or more reducer. Then we need several React components to render the UI. We also need several Action orders corresponding to reducer, as shown in the figure above. Reducer in store is combined to form a data warehouse of the project. Redux calls it state (we simply understand it as data), and the React component can obtain data by subscription to store. However, the data flow in React is one-way, so the UI component cannot directly modify the data in the Store. Therefore, the UI must send Action instructions to the Store to make the store modify itself. The distribution process of this instruction is called dispatch. When the action instruction reaches the store, it may be preprocessed by several middleware for data, such as asynchronous data processing, which is carried out here. After the preprocessing is completed, the data will be transmitted to Reduce together with the action. Reduce will update the data state according to the instructions described in action. When the state is updated, Store will immediately push the new data to the component that subscribes to it, and then the component will re-render the UI and feed back to the user

It can be seen that the redux architecture is quite complicated in practice, but this architecture diagram is not a guide to persuade people to quit. For those who hear so many unfamiliar terms for the first time, please do not panic. Next, we simplify the process in the diagram, reserving only the four parts of Store, Action, Reducer and Component. Then you get this picture, which makes it a little clearer:

Store stores global data. For a project using redux architecture, there is only one store (unique). We can regard store as a data warehouse with push function, and we can use wechat moments to understand this concept: Store represents your moments of friends, which contains all kinds of friends' information, and Component represents your own wechat. If you add someone as a friend and he posts in moments of friends, the status of his moments of friends will be immediately pushed to your wechat. Adding friends is like data subscription, while Posting in moments of friends is like data push. So what is reducer? Theoretically speaking, it is a method to help store process data. Please note that Reducer is a method, a process and a function, rather than a concrete object, which can help store initialize data, modify data and delete data. However, why do we use such a troublesome way to process data? Instead of operating directly in the Store? Let's go back to our example, for example, you saw a wrong character in your moments, can you modify the content of others' moments in your own wechat? And the answer, of course, is no, you don't have permission to modify other people's moments, and that's how it works in our store. No UI level component has permission to modify the data in the Store. According to redux, data flows in one direction. If this message in the moments of friends typos to correct, how should we do? Of course, you should inform your friend and instruct him to modify this message by himself. This instruction to inform your friend is action, the process of informing your friend is dispatch, and the process of your friend to modify the circle of friends is reducer. Finally, when your friend modifs the circle of friends, Wechat will push the modified message to you again. This whole process is subscription and push!

Let’s summarize:

  • Store: A data warehouse with push functionality
  • Reducer: Data processing method that helps the Store complete various operations on data
  • Action: data update instruction, which tells Reduce how to process the data

That’s it. Now let’s go into code and get to know redux in action:

First, we implement a counter function, click the plus sign, the number increases 1, click the minus sign, the number decreases 1

Note that redux’s four core functions need to be understood before going into action:

// Initialize the store
const store = createStore(reducers);

/ / for the state
store.getState();

// Trigger action to request data modification
store.dispatch(action);

// The subscription data changes callback function
store.subscribe(() = > {});
Copy the code

First, create a repository: createStore

Create a new index.js file and install redux as follows:

import { createStore } from 'redux';

const store = createStore();

export default store;
Copy the code

Step 2, create the directive: Action

Create a new actions.js file for actions. Since our function has two actions, add and subtract, we need to create two actions:

export const addAction = { type: 'add' };
export const subAction = { type: 'sub' };
Copy the code

Step 3 Create a Reducer

Create a reducer. Js file that is specially used to store reducer. Before creating reducer, we need to initialize data, and the default value here is 0:

const defaultState = {
    number: 0};const reducer = (state = defaultState, action) = > {
    switch (action.type) {
        case 'add':
            return { number: state.number + 1 };
        case 'sub':
            return { number: state.number - 1 };
        default:
            returnstate; }};export default reducer;
Copy the code

Reducer once created, remember to pass createStore:

import { createStore } from 'redux';
import reducer from './reducer';

const store = createStore(reducer);

export default store;
Copy the code

Step 4, complete the business code

Create an index.html file with the following contents:

<! DOCTYPEhtml>
<html lang="en">
<head>
    <script src="./main.js"></script>
</head>
<body>
    <div id="num">0</div>
    <button id="add">I'm a bit</button>
    <button id="sub">Point I lost</button>
</body>
</html>
Copy the code

Create an index.js file with the following contents:

import store from '.. /redux/store';
import { addAction, subAction } from '.. /redux/actions';

window.onload = () = > {

    // Get the page element
    const numDiv = document.getElementById('num');
    const addBtn = document.getElementById('add');
    const subBtn = document.getElementById('sub');

    // Bind the event, click the plus sign, call dispatch, and increment the number by 1
    addBtn.onclick = () = > store.dispatch(addAction);

    // Bind the event, click the minus sign, call dispatch, and subtract 1 from the number
    subBtn.onclick = () = > store.dispatch(subAction);

    // When data changes, get the latest number value from store and render it to the page
    store.subscribe(() = > {
        const { number } = store.getState();
        numDiv.innerHTML = number;
        console.log(numDiv.innerHTML);
    });
};
Copy the code

Open your browser, click the button, and you can see that the addition and subtraction operations are without any problems!

And there we are, using Redux to complete a simple counter function!

In the above implementation, there are no arguments and the default step is 1, but think about this: what if the value we want to add or subtract is not 1, but an arbitrary value? In this case, you need to carry parameters. How do you do that? Write the parameters in the action. It is easy to change only two places:

    1. Add a field to the Action object. The new field is the parameter we need
// Change actions from normal objects to functions that return an object:

export const addAction = step= > ({
    type: 'add'.number: step,
});

export const subAction = step= > ({
    type: 'sub'.number: step,
});
Copy the code
    1. Modify the business code:
// When called, the action becomes a function and requires an argument

// Click the plus sign, call dispatch, and add 10 to the number
addBtn.onclick = () = > store.dispatch(addAction(10));

// Click the minus sign, call Dispatch, and subtract 666 from the number
subBtn.onclick = () = > store.dispatch(subAction(Awesome!));
Copy the code

OK, so you can carry parameters!

Step 5, embed React

For better understanding, it is not used with Vue or React. Instead, it is written in native JS completely independently. Here we embed it in React: