preface

I wrote an article about building a simple version of Douban based on VUE before. Recently, I came into contact with React, so I rewrote the project with React to experience the similarities and differences between the two in actual development. This article will briefly describe the project situation and some scattered problems encountered in the process of building the project, for record, superficial knowledge, if there are mistakes and omissions, please correct them.


Description of project

Project address: React-Douban

Project Introduction: Build a simple version of Douban based on React, realizing the function of displaying books, movies, music, local activities and other contents according to different types.

Technology stack: React + Mobx + React-Router + AXIos + Sass + ES6/7, etc. At the same time, ESLint, Stylelint, Prettier and other excellent open source tools were used to adjust the constraints of the project to ensure the code quality and uniform style.

Project Background: The interface style of this project is from Douban, and the data is obtained from the official API of Douban. Due to the request limitation, frequent requests will lead to request failure, which should be noted.

Development environment: Node V8.1.2, NPM 6.1.0, YARN 1.7.0; Browser: Chrome 67.0.3396.99, Firefox 61.0.1.


Run the project

Before running the project, ensure that the Node environment is properly installed.

  • If the Git environment is not installed, you can also download the installation package from the React-Douban.

git clone https://github.com/nh0007/react-douban.git
Copy the code

  • Go to the project root directory and install dependencies.

npm install 
or 
yarn install
Copy the code

  • After installing dependencies, run the project;

npm start
or
yarn start
Copy the code

  • After the operation is completed, the browser will automatically pop up the access page, and you can see the operation effect of the project.


Project screenshots

This project is mainly divided into four modules: reading, film, music and city activities. The following are the screenshots of each module:


















Issues needing attention in development

1. Initial project configuration

As the saying goes: well begun is half done. The addition of inspection configuration at the beginning of the project is the cornerstone of the later development of the project. So, after building the project using the create-React-app scaffolding, to add custom configurations, eject the project and then add the following configuration:

  • Check code quality using Airbnb inspection rules;
  • Use the Prettier tool to unify code style;
  • Use stylelint to check the style code;
  • Husky, Lint-staged validation of code about to be delivered.

At the beginning of contact with these configuration friends may be very uncomfortable, even irritable, configuration after the development process always error, affecting the progress. But it’s still a cost to pay, especially if you’ve managed to maintain some “messy” code. For specific configurations, you can view the submission record, in which you can submit and modify the configurations. If you’re still a little confused, there’s a video on YouTube that explains the initial configuration and how to use it with the editor plug-in in less than 10 minutes. It’s pretty clear, if you’re new to it.


2. A few DOS and don ‘ts when using Mobx

  • Add decorator syntax configuration, I am more used to decorator syntax, related configuration can be seen here;
  • All Observable data is modified in an Action, whether stored in a store or component.
  • When using action to change the state, you can use the arrow function to ensure that no matter how you call the function, this is pointing to the error, as follows:

@action
setCurrentBookTags = tags => {
  if (tags.tagName !== this.currentBookTags.tagName) {
    this.currentBookTags = tags;
  }
};
Copy the code

  • The official documentation for asynchronous change status recommends using flow, which makes asynchronous code simpler by wrapping it without the @Action or runInAction. There are two things to be aware of when using ESLint: first, you need to introduce flow, otherwise you will get an error (can I say that at first I thought I had to change the ESLint configuration for a while); The second is to bind this. Example code is as follows:

Import {Observable, action, flow} from mobx'mobx'; / / asynchronous data need to bind this, no matter you are enclosing props. BookStore. SetTypeBooks (type) call, // still const {setTypeBooks } = this.props.bookStore; setTypeBooks(type); No errors can be made;setTypeBooks = flow(
  function* (type, start, count, isAfresh = false) {
    const oldData = this.typeBooks.get(type);
    if(oldData && ! isAfresh)return;
    try {
      const response = yield getCurrentTypeBooks(type, start, count);
      const data = response.data.books;
      this.typeBooks.set(type, data);
    } catch (error) {
      console.log(error);
    }
  }.bind(this)
);
Copy the code

  • In Mobx4, PropTypes. Array is an observable array, so you can’t use PropTypes. In Mobx5, you can use Proxy to track changes.
  • ObservableMap (mobx-React observableMap) is more suitable for type checking than PropTypes. ObservableMap (Mobx-React observableMap) can be used for type checking. PropTypes in mobx-React and prop-types in Mobx-React have the same name problem:

import { observer, inject, PropTypes as mobxPropTypes } from 'mobx-react';
import PropTypes from 'prop-types';
Copy the code


3. Realization of round seeding

In the project, there are a lot of pages showing content in rotation. There are some problems encountered in the implementation process, which are recorded here.

First take a look at the rotation effect of the project:



Although there are some excellent rote libraries, this is not a dedicated rote library, but with transition, animation effects to achieve.

React and Vue use transitions and animations differently:

  • React can be assisted by the react-transition-group library.
  • In Vue, v-if and V-show can be combined to control the display of hidden animations. In react-transition-group, its in attribute is mainly used.

About the use of react-transition-group, the most clear and detailed official documents are available. There are a lot of Chinese materials on the Internet that introduce the early VERSION of V1, which needs to be matched with its own version.

Take a look at the official documentation for in:

Show the component; triggers the enter or exit states

type:
boolean
default:
false

Transition state is toggled via the in prop. When true the component begins the “Enter” stage. During this stage, the component will shift from its current transition state, to 'entering' for the duration of the transition and then to the 'entered' stage once it’s complete.

When in is false the same thing happens except the state moves from 'exiting' to 'exited'.

In simple terms, a change in value alters the state of the transition component:

  • When the in value changes from false to true, the component enters the Enter state.
  • When the in value changes from true to false, the component enters the exit state.

Change is emphasized because in practice, when you first mount the CSSTransition component it has an in value of true, it does not trigger onEnter, it does not add the corresponding state class to the corresponding container element, This will only happen if it changes from false to true. False in the same way.

Vue uses a similar
component package list to perform transitions. React doesn’t work with the following code:

import React, { PureComponent } from 'react';
import { TransitionGroup, CSSTransition } from 'react-transition-group';

export default class Slider extends PureComponent {
  ...
  render() {...return (
      <TransitionGroup className="slider-list">
        {itemArray.map((item, index) => (
          <CSSTransition
            key={item.id}
            in={currentPage === index}
            timeout={500}
            classNames={`slider-${slideDirection}`}
            unmountOnExit
          >
            ...
          </CSSTransition>
        ))}
      </TransitionGroup>
    )
  }
}
Copy the code

At first, I thought I was using TransitionGroup and CSSTransition incorrectly, or missing some important properties. I looked at the document for a long time, but it still didn’t work, and the in and unmountOnExit Settings for CSSTransition components didn’t work either. Then try changing the TransitionGroup tag to a div tag. In my opinion, I made a mistake by understanding TransitionGroup at the beginning. TransitionGroup should be used to render the whole list at the same time, such as adding and removing lists. It is obviously not appropriate to show only one item in the list at a time, such as round casting.

To sum up: in this project, the CSSTransition component of react-transition-group is used to realize the rotation animation. In and unmountOnExit are used to control whether the animation is displayed or not, and the transition effect is achieved by using classNames attribute and style. Specific implementation can refer to the source code, here is no longer described.


4. Component separation

Before starting this project, I read some articles on React best practices online, and one common point was to split components for reuse and maintenance. Too large components there is no doubt that is necessary to break up, but only depends on the size of the component split is rough, component separation standard is what, the official documentation to mention is that a single functional principle, writing code for a single functional principle must not unfamiliar, but the principles used in the component split, or met with the following questions:

  • Dividing components according to the principle of single function may lead to the increase in the number of components and the fragmentation of components.
  • Business components are often so different that they are used only once, not only failing to reuse, but also adding more code.
  • Multi-component means that properties are passed between more components, and the frequent switching of component files during development is often cumbersome.

So we don’t split it? No, component separation has another benefit, is to optimize performance, details can be seen in this article, written very clearly, here is a brief summary:

By default, the component state is updated, and the child component performs re-render and vDOM-diff operations even if the state is unchanged.

Ideally, if the component state is unchanged, no additional action is required.

How to achieve the ideal situation?

  1. Reduce the need for extra operations using the return value of shouldComponentUpdate lifecycle function, which can be implemented by default with PureRenderMin or PureComponent;
  2. ShouldComponentUpdate alone is not enough, the more the state of the component is affected, the more operations such as component re-render are performed, and the more likely it is. Therefore, it is necessary to split components by flattening them.

Well, to summarize, when do you need to split components?

  • If the component is bloated, you can consider splitting the component to improve the readability of the code and facilitate later maintenance.
  • If there is room for component performance optimization, you can split components to reduce potential performance risks.

How to break it up?

  • According to the single function principle, make the component responsibility clear;
  • Partition according to state, so that the partitioned components can minimize unnecessary update operations.

Finally, take a look at an example from a project:



When I click on the next page, the previous page gradually disappears and the next page is gradually displayed. The other two paging pages remain unchanged. When I put the four paging pages into one component without splitting the component, each paging page will be updated every time the number of pages currently displayed changes. To execute the re-render and vdom-diff operations, the sample code is as follows:

{bookList.map((bookArray, index) => (
  <ul
    key={bookArray[0].id}
    style={{display: currentPage === index ? 'block' : 'none'}} >... </ul> ))}Copy the code

At this time, we can consider splitting components, so I split each paging page into independent components, so that when I slide from the first page to the second page, only the first and second pages need to be updated due to state changes, while the third and fourth pages do not need to be updated. The sample code is as follows, and the specific code can be seen in the source code:

{bookList.map((bookArray, index) => (
  <BookTagDisplayItem
    key={bookArray[0].id}
    isShow={currentPage === index}
  />
))}
Copy the code

The above are some subjective thoughts and practices on component separation for reference only. Personally think component split is a metaphysics, component granularity is an abstract and there is no absolute answer. We seldom meet a component swollen so that must be split, and in the case of interface elements is not much, we rarely meet the component does not break up that would have tremendous influence on the performance of the situation, the more time we met is a detachable doesn’t hurt, split, broken, for no reason and a lot more files; Do not open, and a little obsessive compulsive disorder, how to grasp the degree of separation is also a knowledge. Of course, it may be the reason for thinking more and doing less. I hope I can find a balance point in too much practice in the future.


React User Experience

  • React uses JSX to build page elements. It may be a bit awkward at first, but if you have a basic JS background, JSX is not expensive to get used to.
  • When using React, I will subconsciously think about whether components need to be split. I used to think about this issue when using other frameworks, but I think the granularity of React is finer. Of course, what is the degree of split?
  • Redux, Mobx, redux, redux, redux, redux, redux, Redux, Redux You have options like Redux-Thunk, Redux-Promise, And Redux-Saga. In terms of Redux best practices, you might also get dVA or Rematch. How to screen out the information suitable for oneself is also a test of ability.


conclusion

I feel my understanding of React still needs to be improved. If there are any inaccuracies in the text, PLEASE criticize and correct me. If you find it helpful, please don’t bother to star this project