Writing in the front

It has been more than half a year since I started to contact ES6 and UMI technology stack in July, 2000.

In order to complete the teacher’s project, I learned how to write a JSX page with REACT + ANTD in UMI, and used DVA to realize model processing data flow and logic. Even THE architecture of MVVM was completely unclear. At the beginning, I just followed the project on Yuq. How the DVA implemented model is bound to the JSX component and how the component gets state from the Model is completely unknown.

Slowly through the training of several projects, I gained a new understanding of React, and understood why React+Redux can realize MVVM mode. I also understood how the data of each model came from, where it was stored, and how components got the data. I just know how to use it, but I don’t know why to write it like this, and what is the purpose of writing it like this. The most funny thing is that every time I write a model, I copy the code of the previous model and modify it.

This period of time to prepare for the internship interview, crazy to study the knowledge of all the official documents related posts in communities and saw a lot of knowledge about dva, finally let me see the glimmer of light, also dare to write article in plain language to record their understanding of various points in the technology stack, is summarized, also be to own a test, Let’s see if I really understand. This is also the first article written in the nuggets, can come back to see when confused later.

If there is a bad place to write, you are welcome to correct, I am not sure that their understanding is correct T _ T, also hope to learn more here slowly progress!

1. React

What is React? Check out the React description:

React is a JavaScript library for building user interfaces.

React features:

Declarative: React makes creating interactive UIs a breeze. Design a concise view of every state in your app. React effectively updates and renders components correctly when data changes. Writing your UI declaratively makes your code more reliable and easy to debug.

Componentization: Create components that have their own states, and then form a more complex UI from those components. Component logic is written in JavaScript rather than templates, so you can easily pass data around your application and keep state separate from DOM.

Learn once, Write anywhere: No matter what technology stack you’re currently using, you can always introduce React to develop new features without having to rewrite existing code.

As for the third point, because I have only carried out PC web front-end development and only come into contact with umi+ DVA technology stack, I do not have a very deep understanding of this point.

React is a JavaScript library that allows you to create DOM nodes in JavaScript that will be displayed on the page. This is called a component in React

const element = <h1>Hello, world! </h1>;

This is called a component, and this is called JSX. What’s the advantage of doing this? Imagine if you have a div and you want to render ten h1 headings with text from 1 to 10. If you use the original HTML template, do you have to write ten H1 headings, or do you have to write srcipt at the end of the HTML? Select the div, create the H1 with a for loop, insert it into the div and loop 10 times. What does it say in JSX (umi)?

import React; const Index = (props) => { const arr = []; for(let i = 1; i<=10; i++){ arr.push(i) } ... return( <div> { arr.map(item => ( return(<h1>{item}</h1>) )) } </div> ) }; export default Index;Copy the code

I think this is the most important idea of React. It treats HTML elements like classes that can be used to render elements on the page. It’s like introducing object-oriented thinking into front-end programming. Each large component is a class that has its props and its own state. When the props and state change, React updates the component based on actual usage.

After encapsulating each component into a class, React actually makes sense. It has a part of the code that handles element rendering, the JSX code in Renturn, and a part of the code that handles the data inside the component, the logic for props and state, and the rest of the code in this class.

When I first learned React, I used Class to write components. However, after looking at antD code more, I found that using the arrow function method is simpler and more readable. There was a period where class was mixed with arrow functions. The use of arrow functions instead of classes is mostly due to React Hook. In particular, the useState hook allows the arrow function to set state without this. Except for the useState and useEffect hooks, the other hooks are rarely used.

Say so many, in fact just want to express, when you can use js code to deal directly with the HTML element, and the page component interactions, the control component updates will be more convenient, used the object-oriented thought to encapsulate components, each part separate page, isolate their respective internal logic also let code maintainability, readability is stronger.

React uses props and state as the control points of a key subcomponent. This control point is a bit abstract. For example, in the code above, the arR array is a key point. If you use arR as the state of the Index, when the ARR is updated, the Index will be updated locally based on the arR change.

Here a mouth = =, like an array, object such a reference type, we may think to add an element to delete an element to modify an element is the update arr, actually the change of the reference elements in js, must be the change of the memory address, which means it judge you if this is a new reference element will only address does not look at value, Therefore, if the ARR is used as the state control component, to trigger the update of the component, you must slice the updated one each time and assign it to the ARR.

For example, the Table in the ANTD component has an attribute dataSource. Assigning a state OBJ to the dataSource, the OBJ changes the Table and rerenders the Table. For example, display in style, we could say style = dp === 0, right? ‘block’ : ‘none’, then you can use the dp value to control whether the element exists or disappears. This dp must be either state or props.

If a single page application becomes complicated, with more and more internal states and processing logic, react will inevitably be overwhelmed because there are too many states in the actual page, as quoted on Redux’s official website

These states may include server responses, cached data, locally generated data that has not yet been persisted to the server, as well as UI states such as active routes, selected labels, whether loading activity or pagers are displayed, and so on.

So the motivation for Redux arises, to effectively manage all state changes on a single page.

Redux is a JavaScript state container that provides predictable state management.

2. Redux

In fact, if you look at the official documentation of Redux, you may not understand it at first, but you can go through it and think about it from time to time as you develop, and you will understand a lot of things over time. When I read the umi technology stack documents given to me by my upperclassman, I had no idea what I was talking about at the beginning. However, after half a year, I turned them over for several times and gained a lot.

Redux’s three principles:

Single data source: The state of the entire application is stored in an object tree that exists in a single store.

State is read-only: the only way to change State is to trigger an action, which is a generic object that describes events that have occurred.

Use pure functions to perform modifications: To describe how an action changes the State Tree, you need to write reducers.

There are a lot of new concepts involved. Take your time.

You imagine, there is now a application, there are many, many pages, pages, of course, there will be a component, a component will have the state to control, but now some page state is too much, too complicated, if there is no matter the application, various pages in separate code to handle its own state, not only the code, And it’s possible that the state of one page refers to the properties of a component on another page.

So the app came up with an idea, let’s build a warehouse, which has a lot of rooms, put all the states into their own rooms, and take the states from the warehouse for each page. This is a single data source in the Three principles, and all the states will be managed in one store.

I’m just pulling the state data out of the page, but I don’t care about the logic of changing the state. If the page is given a state, it can change whatever it wants, so the app has another solution. It locks all the rooms and doesn’t allow you to change the state directly. You have to follow my logic. This brings us to the second principle: State is read-only, and attempts to change State can only trigger actions. I’ll tell you what action is later.

Okay, now the lock is locked, so what do you want to change. Give you a key that you can use to open the door of your room so you can change the state, and that key is reducers, which is Redux’s third principle, using pure functions to change the state.

Through these three principles, Redux implements one-way data flow control over all states: when all states are stored in the repository, state only flows out of the repository and cannot be added to the repository by the page. In other words, the application defines the state in each room in the repository from the beginning, and the page can only be used, not inserted into its room.

Now you have a look at an example that translated from www.yuque.com/flying.ni/t…

The sample background is one of the most common examples of Web classes: TodoList = TodoList + Add Todo Button

Here’s an example of a React page. The top component of the page is called App, with a TodoList and an add button:

Take a look at the illustration with Redux:

Notice the difference? The state of App was removed and put into a room in the Store, which was not named here because there is only one room. The key of this room is in the reducers below, and only by calling the function in the reducers can you change the state. This is the blue box of dispatches in the page where components connect to the warehouse.

Dispatch accepts a parameter, which is the action not explained above. Action is an object with two attributes. The first is type, and the second parameter is the data to be passed to a reducer name in the reducers to be used.

What connect is, you can simply think of it as a binding component and some state in the repository.

The purpose of Redux is now clear: it is a management tool for all page states. It removes state and state modification logic from all pages and controls data flow only in one direction.

But now there is a problem, reducers are still synchronous functions, but we know that in many cases, the data of the page needs to be obtained from the back end, then what if there are asynchronous functions in reducers, for example, if Add is an asynchronous function, It needs to post data to the backend server and then update TodoList according to the results. According to the current processing logic, the reducer has updated the state before the background returns the results, which will definitely cause unnecessary trouble. This is where redux-Saga comes in!

3. Redux-Saga

As mentioned above, Saga is actually to solve the asynchronous reducer problem existing in Redux. It was not mentioned above that the process of reducer triggering by redux dispatch sending actions to store can be intercepted, so various middleware can be added naturally in this process. To implement various custom functions, and Saga actually implements the ability to handle asynchronous operations.

Sagas is implemented as a Generator function. If you are not familiar with sagas, check out ruan yifeng’s ES6 tutorial. Each saga is a generator function that yields an object to the Redux-Saga middleware. The yielded object is usually an instruction that the middleware can execute. When the middleware gets a yield Promise, the Middleware suspends the saga. Until the Promise is fulfilled. As you can see from generator functions, this function can be pieced internally, but is controlled by the iterator’s next() method. Saga implements such a function that, at the first yield, Wait until a Promise(usually an asynchronous request such as an HTTP request) following yield is returned, and then resume the saga. This is done by executing the code following yield, usually by requesting the Reducer update state.

Let’s take a look at the illustration with redux-Saga added:

We’ll give the saga yield object a name, effect, and add an Effects box to the room to put Effect inside.

4. Redux-Router

I haven’t seen much of this either, but my understanding is that when the app goes to a particular page, it triggers a certain behavior. Subscription in Dva is the redux-Router reference.

For example, subscription is required to trigger an action to send an HTTP request for user data to be displayed in a component of the home page as soon as you log in to the main page, which is routed to /main.

Subscription is used for other actions, such as keyboard actions.

5. Dva

Now that Redux, redux-saga, and redux-Router have more or less been sorted out, it’s time to talk about Dva.

Router redux-saga redux-router redux-router God said, “I need a system for managing state,” and Redux appeared. God said, I need a middleware that can operate asynchronously, so Redux-Saga came along; God said, “I also want to deal with the data flow caused by routing changes.” So redux-Router appeared. God says I want it all, and Dva appears. I even laughed when I finished writing it

So let’s think back to what we said earlier, in the big warehouse store for state, there’s a bunch of rooms, and each room has a page. Redux-saga added Effect to the reducer. Redux-router added subscription to the Reducer. Each page of the room must have its own name, and two must not be the same, or how to distinguish, so we add a namespace attribute, as the unique identifier of the room. Finally, give these rooms another name. It’s unprofessional to keep calling them ‘rooms’. Call them Model.

This is the overall framework for Dva, which has rounded out the original Redux framework and added saga and Router to handle more complex events. Take a look at the diagram with Dva:

Here’s what a classic model looks like:

app.model({ namespace: 'count', state: { record: 0, current: 0, }, reducers: { add(state) { const newCurrent = state.current + 1; return { ... state, record: newCurrent > state.record ? newCurrent : state.record, current: newCurrent, }; }, minus(state) { return { ... state, current: state.current - 1}; }, }, effects: { *add(action, { call, put }) { yield call(delay, 1000); yield put({ type: 'minus' }); }}, subscriptions: {keyboardWatcher ({beat} {key (' ⌘ + up and CTRL + up, () = > {dispatch ({type: 'add'})}); }, setup({ dispatch, history }) { history.listen(({ pathname }) => { if (pathname === '/') { dispatch({ type: 'add', }); }}); }},}});Copy the code

The graphic on the Dva website says:

Dva, based on the best practices of React + Redux + Saga, does three important things that greatly improve the coding experience:

  1. Unify store and Saga into a model concept and write it in a JS file

  2. A Subscriptions subscription was added to collect actions from other sources.

  3. Model is very simple, like DSL or RoR, and coding is very fast

Now I finally get the general idea T_T.

6. Umi + Dva

What is UMI? The document my upperclassman gave me was as follows:

Umi is a React application framework that integrates functions such as route management, front-end plug-in system, project resource packaging, and syntax compilation, helping developers quickly create a complete system of React projects. This scaffolding makes it easy to create React projects.

For me, UMI is a scaffolding that allows me to easily use React + ANTD + Dva + other js libraries that can be installed. The development experience is really cool.

It is much easier to use DVA in UMI, it is completely 0 API, now put the above model into UMI to write, and then bind the page to see how to implement.

Installation umi process is omitted, the official website has a very detailed introduction. JSX (SRC /models/) and model.js(ts) (ts, ts) in the pages folder. Is considered a model.

Write the following code in index.jsx:

import React from 'react;

const Index = (props) => {

    return(
    <>
    ...
    </>
    )
}

export default Index;
Copy the code

This is the most basic page to write, where is its state, don’t worry, let’s write model.js.

const Model = { namespace: 'count', state: { record: 0, current: 0, }, reducers: { add(state) { const newCurrent = state.current + 1; return { ... state, record: newCurrent > state.record ? newCurrent : state.record, current: newCurrent, }; }, minus(state) { return { ... state, current: state.current - 1}; }, }, effects: { *add(action, { call, put }) { yield call(delay, 1000); yield put({ type: 'minus' }); }}, subscriptions: {keyboardWatcher ({beat} {key (' ⌘ + up and CTRL + up, () = > {dispatch ({type: 'add'})}); }, setup({ dispatch, history }) { history.listen(({ pathname }) => { if (pathname === '/') { dispatch({ type: 'add', }); }}); }},}Copy the code

Index () {index () {index ();

import React from 'react;
import { connect } from 'umi';

const Index = (props) => {
    const { Count, dispatch } = props; 

    return(
    <>
    ...
    </>
    )
}

const mapStateToProps = (props) => {
    const { count } = props;
    return {
        Count: count,
    };
};

export default connect(mapStateToProps)(Index);
Copy the code

So that binds. I didn’t understand it for a long time until I went through the official documentation of REdux and DVA. I don’t know because I don’t have a warehouse, I don’t know where count comes from. As mentioned earlier, all rooms are stored in a repository. Naturally, all model states are stored together in a global store. The name of a model’s state in the global store is the namespace of the model.

To find the store, we introduced Umi’s connect method, followed by two parentheses, to bind data to the page. So the first parenthesis is to get the data, so we’re going to define a function, and when we put that function in the first parenthesis, this thing is going to be the store, and you’re going to extract count from the store. If you define a few more models, you’ll find that all the namespaces of the models can be found in the store, representing the state of each model, so this solves another important problem: communication between two pages. If two pages are bound to a state, Then the state data can be shared with them.

After the component name is in the second parenthesis, you can find the data returned by the function in the first parenthesis in the props of the component. State is bound by using this data as a key point in component rendering. Of course, dispatches for tasks can also be found in props!

This gives you an idea of how MVVM is implemented.

Let’s go over the dVA data flow chart in UMI one last time:

conclusion

I consulted a lot of official documents, especially the DVA diagrams in the community on the DVA official website, which really inspired me a lot. The above are a few personal views, said the wrong welcome correction ah!

Along the way, I really feel like I have to figure out how something works, and I have to understand why it appears, like Promise in ES6, to solve callback hell, so I know this is a chain call. Then it is to see more excellent code, when I write it is really a piece of shit, what can not, later read the code of other graduate students, read antD official template code, benefit can only say.

Keep learning and keep improving.