The introduction
I have been using react.js for some time, and I have recorded the small pits and tips encountered in the process of using it, hoping to help others. This article is a long one. You can only grow if you can resist loneliness and temptation.
I. Tools
1. Display HTML
<div dangerouslySetInnerHTML={{ __html: LANG.auth_register_tips1 }}/>Copy the code
2. Common components
axios
(http
Request module, can be used for any front-end scenario, very powerful)echarts-for-react
(Visual chart, someone else’s React based encapsulation of echarts, is good enough)recharts
(Another is based onreact
Encapsulated chart)nprogress
(Top loading bar, nice to use)react-draft-wysiwyg(
Based on the othersreact
Rich text encapsulation, if found other better can be replaced)react-draggable
(Drag and drop modules to find a simpler version)screenfull
(Full screen plug-in)photoswipe
(Image shell layer view plugin, does not rely on jQuery, still pretty good)animate.css
(CSS Animation Library)redux Web
An application is a state machine, and views correspond to states one to one. All state is stored in one objectredux-logger
The logReselect
Memory componentsredux-thunk
To solve the asynchronous action problemredux-saga
To solve the asynchronous action problemreact-router-redux
The route is synchronized with the application statereact-router-dom
React-devtools debugger
Tool address: github.com/facebook/re…
Global installation:
yarn global add react-devtoolsCopy the code
Configuration: Configure it in package.json:
"scripts": {
"devtools": "react-devtools"
}Copy the code
Then start yarn Run devtools
Ii. Component communication
Situations in which components are required to communicate
- The parent component communicates with the child component
- The child communicates with the parent
- Cross-level component communication
- Communication between components with no nested relationship
- Redux architecture
- Parent component to child component — props
- The child component receives parameters from the parent component — props. Funciton
- Leverage the event mechanism
1. The parent component communicates with the child component
React data flow is unidirectional, with parent to child communication being the most common; The parent component uses props to pass the required information to the child component
2. Child components communicate with parent components
- Use callback functions
- Utilize the custom event mechanism
The child component changes the state of the parent component
Const {data} = this.state; this.setState({ data: {... data, key: 1 } }); This.setstate (({data}) => ({data: {... data, key: 1 } })); This.setstate ((state, props) => {return { counter: state.counter + props.step };
});Copy the code
3. Cross-level communication between components
- Pass props to multiple components
For example, to communicate between component A and component B, the common parent component of A and B is found first. Component A communicates with component C first, and component C communicates with component B through props. In this case, component C acts as the middleware
- Use the context
Context is a global variable, like a big container that can be accessed anywhere, so we can put the information that we want to communicate on the context, and then we can get it from other components; React officially does not recommend using a lot of context, although it can reduce layer passing, but when the component structure is complex, we don’t know where the context is coming from; And context is a global variable, and global variables are the ones that cause the application to get messy in the first place.
Use the context
ListItem is a child of List, which is a child of app
ListItem.js
import React, { Component } from 'react';
import PropTypes from 'prop-types'; Class ListItem extends Component {/ / subcomponents declare themselves to use the context static contextTypes = {color: PropTypes.string, } static propTypes = { value: PropTypes.string, }render() {
const { value } = this.props;
return( <li style={{ background: this.context.color }}> <span>{value}</span> </li> ); }}export default ListItem;Copy the code
List.js
import ListItem from './ListItem'; Class List extends Component {static childContextTypes = {color: = ""; color: =" "; Proptypes. string,} static PropTypes = {list: proptypes. array,} // Provide a function that returns the appropriate contextgetChildContext() {
return {
color: 'red'}; }render() {
const { list } = this.props;
return (
<div>
<ul>
{
list.map((entry, index) =>
<ListItem key={`list-${index}`} value={entry.text} />, ) } </ul> </div> ); }}export default List;Copy the code
App.js
import React, { Component } from 'react';
import List from './components/List';
const list = [
{
text: 'Topic one',
},
{
text: 'Problem two',},];export default class App extends Component {
render() {
return( <div> <List list={list} /> </div> ); }}Copy the code
4. Communication between components without nested relationships
- Use a custom event mechanism
In the componentDidMount event, subscribe to the event once the component has been mounted. Unsubscribe from componentWillUnmount event during component unmount. For a common publish/subscribe pattern, borrow the browser version of the Node.js Events module
Using custom events
In the following example, List1 and List2 do not have any nested relationship. App is their parent.
Implement the ability to change the display of information in List1 by clicking a button in List2
First you need to install the Events package in your project:
npm install events --saveCopy the code
Create an events.js under SRC in a new util directory
import { EventEmitter } from 'events';
export default new EventEmitter();Copy the code
list1.js
import React, { Component } from 'react';
import emitter from '.. /util/events';
class List extends Component {
constructor(props) {
super(props);
this.state = {
message: 'List1'}; }componentDidMount() {// Declare a custom event when the component is loaded. This.eventemitter = Emitter.addListener ();'changeMessage', (message) => {
this.setState({
message,
});
});
}
componentWillUnmount() {
emitter.removeListener(this.eventEmitter);
}
render() {
return( <div> {this.state.message} </div> ); }}export default List;Copy the code
List2.js
import React, { Component } from 'react';
import emitter from '.. /util/events';
class List2 extends Component {
handleClick = (message) => {
emitter.emit('changeMessage', message);
};
render() {
return (
<div>
<button onClick={this.handleClick.bind(this, 'List2')}> Click I change List1 component display information </button> </div>); }}Copy the code
APP.js
import React, { Component } from 'react';
import List1 from './components/List1';
import List2 from './components/List2';
export default class App extends Component {
render() {
return( <div> <List1 /> <List2 /> </div> ); }}Copy the code
Custom events are a typical publish-subscribe pattern that enables communication between components by adding listeners to event objects and firing events
OnRef method for communication between components
There is also an onRef method for inter-component communication in addition to props, but the React official documentation recommends against relying too much on the REF. This article uses the onRef context to extract the common components at form entry and the form information at submission.
In the following demo, click the parent component button to obtain all the information of the child component, including the status and method. You can see the console print in the Demo.
Class Parent extends React.Component {test} handleClick=()=>{alert(this.child.state.info) // -> {alert(this.child.state.info) }}}}}}}}}render() {
return<div> <Child onRef={this.testref} /> <button onClick={this.handleclick}> Parent button </button> </div>}} // Child class Child extends React.Component { constructor(props) { super(props) this.state = { info:'Click on the child component button ha ha ha'}}componentDidMount(){this.props. OnRef (this) console.log(this) // -> pass child to this.props. OnRef ()} handleChildClick=()=>{this.props. this.setState({info:'Get child information via parent button la la la'})}render() {return<button onClick={this.handlechildclick}> Child component button </button>}}Copy the code
Principle:
When the onRef function is called in a child component, the function passed from the parent component is being called. This.props. OnRef (this) The argument here refers to the child component itself, and the parent component receives the reference as its first argument: onRef = {ref => (this.child = ref)} then it uses this.child to hold the reference. Later, the entire child component instance can be accessed within the parent component and child component functions can be called.
Iii. Routing section
With a single-page app built with React, the first thing you want to do to jump between pages is to use routing. React-router and React-router-dom are two packages commonly used in React. This paper mainly explains react-router-DOM.
1. React Router has three types of components:
- Router components (BrowserRouter, HashRouter)
- Route Matching component (Route, Switch)
- Navigation component (Link)
For a React Router based Web application, the root component should be a Router component (BrowserRouter, HashRouter). In the project, react-router-DOM provides and two routes. Both routes create a History object. If our application has a server that responds to web requests, we usually use the
component; If we are using a static file server, we should use the
component
HashRouter and BrowserRouter
There are two types of routing hash and history (if you don’t know the difference between the two modes).
And these two components are the container for routing and must be in the outermost layer
// hashMode reactdom.render (<HashRouter> <Route path="/" component={Home}/>
</HashRouter>
)
// historyMode reactdom. render(<BrowserRouter> <Route path="/" component={Home}/>
</BrowserRouter>
)Copy the code
Let’s talk about the parameters on HashRouter and BrowserRouter
- For example, if you want to deploy your project to www.xxxx.com/web, set basename=”/web”
- GetUserConfirmation is used to intercept the Prompt component and decide whether to jump
- ForceRefresh is used to set whether to force the entire browser refresh. The default value is false
- KeLength is used to set the length of the location.key. The default is 6 and can be customized
3, the Route
A Route is the raw material of a Route. It is the component that controls the display of the path
The parameters of the Route
- Path Indicates the jump path
- Component Component displayed in the corresponding path
- Render can write its own render function to return the specific DOM without setting the Component
- Location passes a route object, compares it to the current route object, and jumps if it matches
- Exact Specifies the matching rule. True specifies the exact matching rule.
path | url | Whether open | Matching results |
/a | /a/b | false | yes |
/a | /a/b | true | no |
- Sensitive Whether path is case-sensitive
path | url | Whether open | Matching results |
/a | /a | true | yes |
/a | /A | true | yes |
- Strict Specifies whether to match the following /
path | url | Whether open | Matching results |
/a | /a/ | true | yes |
/a | /a/c | true | yes |
/a | /a | true | no |
4, the Router
Low level routing, applicable to any routing component, is mainly deeply integrated with redux and must be used in conjunction with the History object
The purpose of using the Router route isto synchronize with the status management library such as history in Redux
<Router history= {history} >... </Router> Copy the codeCopy the code
5. Link and NavLink
Both routes are hops. NavLink has more parameters
The Link of the API
- There are two ways to write to indicate which route to jump to
- String writing
<Link to="/a"/> Copy the codeCopy the code
- Object to write
<Link to={{
pathname: '/courses',
search: '? sort=name'.hash: '#the-hash',
state: { fromDashboard: true}}}/> Copy the codeCopy the code
- Replace is changing push to replace
- InnerRef accesses the DOM of the Link tag
NavLink API
- All of Link’s apis
- ActiveClassName Class name set when the route is activated
- ActiveStyle Style of route activation Settings
- Exact reference Route. If this condition is met, the active class will be activated
- Strict Refer to Route. The active class is activated only when this condition is met
- IsActive receives a callback function that is fired when the active state changes. Returning false interrupts the jump
const oddEvent = (match, location) => {
console.log(match,location)
if(! match) {return false
}
console.log(match.id)
return true
}
<NavLink isActive={oddEvent} to="/a/123"> component a </NavLink> copy codeCopy the code
- Location receives a location object. The URL will jump only if it meets the conditions of this object
<NavLink to="/a/123" location={{ key:"mb5wu3", pathname:"/a/123"}}/> Copy the codeCopy the code
6, Redirect
Redirect Redirect is easy. We just look at the code
<Redirect to="/somewhere/else"/> <Redirect to={{pathname:"/login",
search: "? utm=your+face"State: {referrer: currentLocation}}} /> <Redirect push to="/somewhere/else"/> <Redirect from= <Switch> <Redirect from= <Switch> <Redirect from='/old-path' to='/new-path'/>
<Route path='/new-path'Component ={Place}/> </Switch> Copy the codeCopy the code
7, the Switch
If you switch routes, only the first route is matched, so you can think of it as the TAB bar
The Switch contains only Route, Redirect, and Router
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/about" component={About}/>
<Route path="/:user"Component ={User}/> <Route Component ={NoMatch}/> </Switch> Copy codeCopy the code
8 withRouter.
When a non-routing component also wants to access the match,location, and history objects of the current route, then withRouter is a good choice. Think of it as wrapping a component as a routing component
import { withRouter } from 'react-router-dom'
const MyComponent = (props) => {
const { match, location, history } = this.props
return( <div>{props.location.pathname}</div> ) } const FirstTest = withRouter(MyComponent); Copy the codeCopy the code
9. History object
The React-Router has both component navigation and programmatic navigation. How do you use the React-Router API to control forward, backward, and refresh? Now we need to explain what the history object does
We can use this.props. History to get the history object from each routing component, or we can wrap the component around withRouter.
Push, replace, go and other methods are encapsulated in history. The specific contents are as follows
History { length: number; action: Action; location: Location; push(path: Path, state? : LocationState): void; Push (location: LocationDescriptorObject): void; push(location: LocationDescriptorObject): void; push(location: LocationDescriptorObject): void; Replace (path: path, state? : LocationState): void; GoBack Replace (location: LocationDescriptorObject): void; // Replace the current path with a page. Go (n: number): void; GoBack (): void; GoForward (): void; // Advance a page block(prompt? : boolean | string | TransitionPromptHook): UnregisterCallback; listen(listener: LocationListener): UnregisterCallback; createHref(location: LocationDescriptorObject): Href; } copy codeCopy the code
So if we want to use the API to move forward and back we can call the method in history
Secondly, it can also be achieved by secretly rotating the History library. The specific case is as follows
import { BrowserRouter } from 'react-router-dom';
const history = require('history').createBrowserHistory(); /** * forceRefresh: bool * Function: when the browser does not support HTML5historyAPI to force a page refresh. */ const supportsHistory ='pushState' in window.history;
<BrowserRouter
history= {history}
basename="/"forceRefresh={! SupportsHistory} > {/* Route entry */}...... </BrowserRouter>Copy the code
10. Route authentication
Fourth, performance
After writing React for a while, I’ve grown to like writing apps using React.
We know that one of the things Facebook used when it launched React was performance.
Today, let’s talk about the performance optimization of React, and think about what other means can be used to improve the performance of React, so that our React faster and better performance.
1. React component performance optimization (render Angle optimization)
1. React performance viewing tool
Before we get into performance tuning, we need to look at the tool that allows us to see how long it takes to load components in React. Before React 16, we could use React Perf to do this.
Before the react16 release, we could use the React-Addons-Perf tool to view, but in the latest 16 release, we just need to add? React_pref.
Let’s start with react-Addons-Perf.
React-addons-perf is an official performance kit from React that prints out component rendering times, times, wasted time, and more.
Briefly say a few API, specific usage can refer to the official website:
Perf.start()
Start recordingPerf.stop()
The end of the recordPerf.printInclusive()
View all designed components renderPerf.printWasted()
View unneeded waste component Render
Install the React Perf extension in Chorme and add the corresponding code in the entry file or redux store.js:
Also, in the latest version of React16, add? React_pref, in chrome performance, we can look at User Timeing to see the component load time. Click “Record” to start recording. Note that the recording duration should not exceed 20 seconds, otherwise Chrome may be suspended.
You can see the following figure for the specific operation of using this tool:
2. Performance optimization of single React component
1. Minimize the number of new variables and bind functions in render, and minimize the number of passed parameters.
Let’s start by thinking about, for example, if I want to implement a button click that increases num by 1, what are the methods we have?
As you can probably imagine, there are no more than three, as shown below:
The first is to bind this to the constructor, the second is to bind this to the render() function, and the third is to use the arrow function.
But which method has the best performance is a question for us to consider. Everyone should know the answer: the first kind of performance is the best.
Because of the first, the constructor is only executed once per render;
And the second way, every timerender()
The function is executed again when the function is executed;
The third way, every timerender()
Generates a new arrow function even if the contents of the two arrow functions are the same.
For the third method, we can give an example. React determines whether render is a shallow comparison, which is simply determined by ===. If the type of state or prop is string or number, as long as the values are the same, the shallow comparison will consider them the same.
But if the former type is a complex object, we know that the object is a reference type, and shallow comparisons only consider these twoprop
Is it the same reference? If not, the two objects are considered distinct even if their contents are identicalprop
.
Here’s an example:
When we assign a prop named style to the component Foo;
<Foo style={{ color:"red" }}Copy the code
With this method, each rendering is considered a style and the prop is changed because each time an object is generated for the style.
If you want React to render with a prop of the same type, you must make sure that the prop points to the same javascript object, as follows:
const fooStyle = { color: "red"}; <Foo style={fooStyle} /> <Foo style={fooStyle} />Copy the code
Custom shouldComponentUpdate function
ShouldComponentUpdate is a function that determines when a React component should not be rerendered, but the default implementation is simply to return true. That is, the default is to call all the lifecycle functions used, including the render function, for each update.
Let’s look at an example below
We write two components, App and Demo, and write two methods, one to change the num value in App, one to change the title, we print the render function in Demo. We can see the following effect:
We can clearly see that although the title value in the demo component has not changed, it is still render.
To solve this problem, we can modify the Demo component as follows:
Only when the title value of the demo changes, we go to render, we can see the effect:
This is just a very simple customization to shouldComponentUpdate.
In the latest react, React provides us with React.pureComponent. The official plugin called React-addons-Pure-Render-mixin was provided earlier to implement the shouldComponentUpdate lifecycle method.
The effect of using the above method is the same as our custom shouldComponentUpdate.
It should be noted, however, that PureRender here is a light comparison, because deep comparison scenes are quite expensive. So we need to pay attention to some of the things we talked about in 1.1: don’t set props or arrays directly, and don’t bind methods directly to elements, because functions are objects too
3. Optimize the performance and key of multiple React components
When the React component is loaded, react creates a tree structure in memory through the render method. The nodes in the tree represent a react component or native Dom element. This tree structure is called Vitural Dom.
React compares the original Vitural Dom and the newly generated Vitural Dom in the update stage, finds out the differences, and then renders the Dom tree according to the differences.
In order to achieve high performance, React uses the time complexity of O(N) to compare the difference between the two attribute structures, because the exact comparison between the two tree structures requires O(N^3), which degrades performance.
Simply put, React uses a key to identify components, which is an id badge, much like our ID cards are used to identify a person.
A list of key
- The key is not passed to the component. If you need to use the value of the key, call it something else
- When a list is reordered, it is not appropriate to use the index of the array as the key
* Note: There is another option: it is recommended to use shortid to generate an array of unique keys and use it with the data array, eliminating the need to reassemble the array when the data is submitted.
Case study:
import React from 'react';
import shortid from 'shortid';
class Demo extends React.Component {
constructor(props) {
super(props);
this.state = {
data: ['a'.'b'.'c']
}
this.dataKeys = this.state.data.map(v => shortid.generate());
}
deleteOne = index => { // 删除操作
const { data } = this.state;
this.setState({ data: data.filter((v, i) => i !== index) });
this.dataKyes.splice(index, 1);
}
render() {
return( <ul> { data.map((v, I) = > < li onClick = {I = > enclosing deleteOne (I)} key = {this. DataKeys [I]} > {n}} < / ul > < / li >))}} / / extraction, slightly can encapsulate a generic componentsCopy the code
It should also be noted that:
The key is not intended to improve react performance, but it does.
You cannot use random to use a key
React updates only component attributes if component attributes change. No changes, no updates.
React destroys the component (constructor and componentWillUnmount) and then recreates it (constructor and componentWillUnmount).
Let’s give you a few examples and you’ll understand right away:
- Different node types
/ / A component < div > < Todos / > < / div > / / B component < span > < Todos / > < / span >Copy the code
We want to update component A to component B. When React made A comparison, it found that the outermost root node was different, so it directly abolished the previous
- The two nodes are of the same type
There are two cases where the node is a Dom type and there is a React component.
For dom types, let’s take an example:
// <div style={color: RGB (0, 0, 0);'red',fontSize:15}} className="welcome"> Hello World!!! <div style={color: # ff0000; color: # ff0000; color: # ff0000;'green',fontSize:15}} className="react">
Good Bye!!!
</div>Copy the code
The difference between A and B components above is that the color in the text, className, and style changes, because the Dom element does not change, React only changes the part of it that changes.
For react component types, rendering is nothing more than going through the update process of the component instance. The most important thing is to customize shouldComponentUpdate, which we also mentioned above, so I won’t go into details.
- Multiple child components
Let’s look at two examples
Example 1:
// A
<ul>
<TodoItem text="First" complete={false} />
<TodoItem text="Second" complete={false} />
</ul>
// B
<ul>
<TodoItem text="First" complete={false} />
<TodoItem text="Second" complete={false} />
<TodoItem text="Third" complete={false} />
</ul>Copy the code
To change from A to B, if shouldComponentUpdate is handled properly, we only need to update the third load once.
Let’s look at the next example:
// A
<ul>
<TodoItem text="First" complete={false} />
<TodoItem text="Second" complete={false} />
</ul>
// B
<ul>
<TodoItem text="Zero" complete={false} />
<TodoItem text="First" complete={false} />
<TodoItem text="Second" complete={false} />
</ul>Copy the code
Since react adopts the time complexity of O(n), it will change the text for First to Zero, then change the text for Second to First, and then add a component at the end, text for Second. The properties of the two existing texts have been changed, so they are rendered in turn.
If we have 1000 instances here, then 1000 updates will happen.
That’s what we’re going to use hereKey
the
Basically, this Key is the REACT component id number.
If we change the previous example to the following, we can avoid the above problem. React can know that the second and third components in B are actually the first and second instances in A.
// A
<ul>
<TodoItem key={1} text="First" complete={false} />
<TodoItem key={2} text="Second" complete={false} />
</ul>
// B
<ul>
<TodoItem key={0} text="Zero" complete={false} />
<TodoItem key={1} text="First" complete={false} />
<TodoItem key={2} text="Second" complete={false} />
</ul>Copy the code
But now, React will remind us not to forget to use the key, and if we don’t use it, we’ll get an error in the browser.
aboutkey
It is important to note that the key value should be stable, as inId numberIt’s the same thing that’s stable for us.
A common mistake is to use the subscript of an array as a key. This is dangerous and should be avoided.
<ul>
{
todos.map((item, index) => {
<TodoItem
key={index}
text={item.text}
completed={item.completed}
})
}
</ul>Copy the code
2. Redux performance optimization: RESELECT (data acquisition optimization)
MapStateToProps is also called selector, and it will be called whenever the store changes, whether or not the data that the selector is interested in changes, so if the selector computation is heavy, recalculating it with each update may cause performance problems.
Reselect can help you eliminate these unnecessary recalculations.
Reselect provides the createSelector function to create memorizable selectors.
The createSelector takes an array of input-selectors and a conversion function as parameters.
If a change in the state tree causes the input-selector value to change, the selector calls the conversion function with input-selectors and returns the result.
If the input-selectors have the same value as the previous one, they will return the data directly from the previous calculation without calling the conversion function again.
This avoids unnecessary computation and results in a performance boost.
Example:
import {} from 'reselect';
export const getItems = (state) => state.cart.get('items');
export const getItemsWithTotals = createSelector(
[ getItems ],
(item) => {
return items.map(i =>{
return i.set('total', i.get('price', 0) * i.get('quantity'); }); })Copy the code
Create a memorized selector. This means that the getItemWithTotals totals will be computed the first time the function is run.
If the same function is called again, but the input value (the value of getItems) does not change, the function will return a cached calculation.
If the items are modified (e.g., item added, quantity changed, anything that operates on the result of getItems), the function is executed again.
In the previous optimization process, we optimized the rendering to improve performance. Since React and Redux both drive the rendering process in a data-driven way, the process of optimizing the rendering process and obtaining data is also an optimization point that needs to be considered.
Const getVisibleTodos = (todos, filter) => {switch (filter) {case 'SHOW_ALL':
return todos
case 'SHOW_COMPLETED':
return todos.filter(t => t.completed)
case 'SHOW_ACTIVE':
returntodos.filter(t => ! t.completed) } } const mapStateToProps = (state) => {return {
todos: getVisibleTodos(state.todos, state.visibilityFilter)
}
}Copy the code
The mapStateToProps function is an important part of retrieving data from the Redux Store. When displaying to-do items based on the filter and todos, we need to walk through an array of toDOS fields.
When the array is large, it degrades performance.
This is where resELECT comes in. It works by using the last cached result as long as the relevant state has not changed.
Specific usage I will not introduce too much here, there have been a lot of cattle people wrote related articles, I will not repeat to write, if you want to understand, you can refer to resELECT giuhub, Redux middleware – ResELECT.
3. Separate code
1. Dynamic loading
The ES6 standard introduces import to make it easier for us to load modules statically. Forms such as:
import xxx from xxx.jsCopy the code
Although import is useful for us to load modules, the way we load modules statically limits us to asynchronous module loading to some extent. However, the import() syntax for dynamically loaded modules is currently in the proposal stage, and WebPack has already introduced it and used it. Import () provides a Promise-based API, so the return value of import() is a Promise object in complete or reject state. Forms such as:
import(/* webpackChunkName: 'module'* /"module")
.then(() => {
//todo
})
.catch(_ => console.log('It is an error'))Copy the code
At compile time, WebPack recognizes dynamically loaded import syntax, and webPack creates a separate bundle for the currently dynamically loaded module. If you’re using the official Create-React-app scaffolding or react’s server-side rendering framework nex.js, you can use the dynamic import syntax directly. If your scaffolding is webpack configured by yourself and you need to follow the official guidelines, go [1].
2. Dynamically load React components
One of the most popular methods is to use the React-loadable [2] library to lazily load the React component. It uses the import() syntax and the Promise syntax to load the React component. Also, React-loadable supports React server rendering. In general, we implement components as follows:
import LazyComponet from 'LazyComponent';
export default function DemoComponent() {
return (
<div>
<p>demo component</p>
<AComponent />
</div>
)
}Copy the code
In the example above, we assume that LazyComponet is not shown when the DemoComponent is rendered. But because we use the import syntax to import LazyComponet, we package the LazyComponet code into the same bundle as the DemoComponent code at compile time. But that’s not what we want. So we can use React-loadable to lazily load LazyComponet and package LazyComponet’s code into a bundle. Take a look at the example provided on the website:
import Loadable from 'react-loadable';
import Loading from './my-loading-component';
const LoadableComponent = Loadable({
loader: () => import('./my-component'),
loading: Loading,
});
export default class App extends React.Component {
render() {
return<LoadableComponent/>; }}Copy the code
As we can see from the example, React-loadable uses the dynamic import() method and assigns imported components to the Loader property. Also, React-loadable provides a loading property to set the component to be displayed when the component is loaded.
Use of lazy and suspense
React.lazy and Suspense is not yet available for server-side rendering. If you want to do code-splitting in a server rendered app, we recommend Loadable Components. It has a nice guide for bundle splitting with server-side rendering.
Before using it, it’s important to note that React is officially supported, but React. Lazy and Suspense do not support server rendering. Therefore, for those who use server-side rendering, please detour to React-loadable and loadable components [3].
Since I am upgrading the original project, the following contents of this article mainly focus on the work I have done in upgrading the React latest version of the old project.
1. Upgrade the code of React latest version
If your code is Reactv16, you can upgrade directly to the latest version, though lazy and suspense methods are already available in React16.6. Before V16, migrate according to the official operation.
2. Identify lazy loaded components of the original code
First, according to the requirements, the components that are not loaded on the first screen are determined to be lazy loaded components. My project identified a total of five components that can be lazy loaded. The modification method is very simple. The original method of introducing components is:
import LazyComponent from ".. /components/LazyComponent ";Copy the code
Is amended as:
const LazyComponent = React.lazy(() =>
import(/* webpackChunkName: 'lazyComponent'* /".. /components/LazyComponent"));Copy the code
Here’s the code: Replace the static reference component code with a call to React. Lazy (), passing an anonymous function as an argument to lazy(), and dynamically introducing lazyComponent into the function. This will prevent the browser from downloading the lazyComponent.bundle.js file and its dependencies before we render the component. WebpackChunkName in import is the bundle name we defined.
What happens when React tries to render a component but the component’s dependent code hasn’t been downloaded yet? Help us out with problems in
return (
<div>
<MainComponet />
<LazyComponent />
</div>
)Copy the code
Is amended as:
returnSuspense ={<div> </div> < Suspense> </div>!!Copy the code
Fallback can be changed to any spinner, this time do not do much optimization. React will give you errors if you don’t use it in suspense, so remember to use React. Lazy with React. At this point, we can see from the network request that the dynamically loaded lazyComponet component is individually packaged into a bundle. However, when the first screen is loaded, the bundle is already loaded into our page, which may not be what we want, we want to load when we need. Then we’ll take the control to load the file when we need it.
3. Control loading through variables
Originally, the five lazy loading components I chose are all of the components of the shell layer, so it is necessary to set a state to control the display and hiding of this component, so we change the code to:
return(< div > < MainComponet / > {this. State. ShowLazyComponent && (< React. The Suspense fallback = {< div > < / div >} in being loaded > < LazyComponent /> </React.Suspense> )} </div> )Copy the code
As a result, the bundle for our lazy-loaded LazyComponent is not loaded on the first screen load. The page does not load the JS until we click to display the component. This accomplishes our goal of code separation and lazy loading. So if we do this, does the size of the main bundle decrease? Next, let’s pack up the files and take a look.
4. Package your files
Files packaged before optimization:
The optimized package files:
The app.js file gets smaller, so add lazyComponent.js. When there are too many components to load lazily, we can reduce the size of the first screen load file to some extent and improve the first screen rendering speed. This experiment only extracts one component as an example, if the number of lazy loading is large, it is enough to significantly reduce the volume of app.js.
Summary — > Verify the effectiveness of optimization
5. [Verify optimization timeliness] Compare Puppeteer and Performance APIS
In order to verify the effectiveness of the previous optimization, I made a group of comparative experiments. In the experiment, puppeteer was used to access the pre-optimized and optimized pages 1000 times respectively, and the Performance API was used to calculate the average value of the five data items during the 1000 visits. The experimental results are shown in the figure below, where:
- A indicates the average request time
- B indicates the average time spent parsing the DOM tree
- C is the average time between request completion and DOM loading
- D is the average time between the start of a request and the end of domContentLoadedEvent
- E indicates the average time between request start and load
The line chart cannot show the data accurately, so the attached table data is as follows (all are average time consuming) :
category | The optimized | Before optimization |
A request (request) |
7.01 | 7.04 |
B(parse the DOM tree average) |
30.28 | 32.59 |
C(DOM loading after request) |
552.86 | 582.0 |
D(request starts at end of domContentLoadedEvent) |
569.13 | 589.0 |
E(request start to load end) |
1055.59 | 1126.94 |
From the data, we can see that the request time before and after optimization has no impact, but the overall load time is significantly shortened and immediately enters the 1000ms mark, which shows that the first screen loading speed is significantly improved after optimization.
Note: While puppeteer is running 1000 times, the network fluctuates and some requests are large, so the average does not fully reflect the normal request time. But an average of 1000 times is enough to compare request times before and after optimization.
6. [Verify the timeliness of optimization] Use Chorme Performance parameters for comparison
Because the Performance API provides limited parameters, I got the parameters for a single page request from Chrome’s Performance summary. Since this is a single data set, we do not make detailed comparisons. It is listed here only to show which parts of the browser render time improved before and after optimization. Before optimization: After optimization:
- Blue: The Loading time decreases
- Yellow: Scripting time decreased
- Purple: Rendering time reduced
- Green: Painting time is flat
- Gray: The Other time is reduced
- Idle: The idle time of the browser decreases
In addition, I found from the Network that after optimization, the request time of the main interface was advanced because the page was parsed faster than before.
4, summarize
According to multiple data, use of React. Lazy and React.Suspense speeds up the first screen rendering to some extent, making our pages load faster. In addition, when we introduce a new dependency when we want to add a new feature, we tend to evaluate the size of the dependency and how much the introduction of the dependency will affect the original bundle. If the feature is rarely used, you can happily use React. Lazy and React.Suspense to load the feature on demand without sacrificing user experience.
Use react.memo () to optimize the performance of function components
Eact16.6 added another one specifically for optimization
Function component(Functional Component) Performance methods:
React.memo.
1. Useless rendering
Look at this example:
import React from 'react';
class TestC extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
}
}
componentWillUpdate(nextProps, nextState) {
console.log('componentWillUpdate')
}
componentDidUpdate(prevProps, prevState) {
console.log('componentDidUpdate')}render() {
return( <div > {this.state.count} <button onClick={()=>this.setState({count: 1})}>Click Me</button> </div> ); }}export default TestC;
Copy the code
The TestC component has a local state, count, with an initial value of 0(state = {count: 0}). When we Click the Click Me button, the value of count is set to 1. The number on the screen will change from 0 to 1. When we click the button again, the count is still 1, and the TestC component should not be rerendered, but is it?
To test whether the component will be rerendered if count is repeatedly set to the same value, I added two lifecycle functions for the TestC component: componentWillUpdate and componentDidUpdate. The componentWillUpdate method is called when the component is about to be rerendered, and the componentDidUpdate method is called after the component has been successfully rerendered.
Run our code in a browser and Click the Click Me button several times. You can see the following output:
We can see that ‘componentWillUpdate’ and ‘componentWillUpdate’ are printed in the console every time we click the button. So even if the count is set to the same value, the TestC component will still be rerendered. This is called useless rendering.
2. Function components
We discussed how to use the PureComponent and shouldComponentUpdate methods to optimize the performance of class components. While class components are the main Component of a React application, Functional components can also be used as React components.
function TestC(props) {
return (
<div>
I am a functional component
</div>
)
}
Copy the code
For function components, They don’t have anything like state to hold their local state (although function components can use useState to do so under React Hooks), so we can’t control the rerendering of function components like shouldComponentUpdate in class components. Of course, we can’t use the extends React.PureComponent because it’s not a class at all.
To explore a solution, let’s first verify that function components have the same problem with useless rendering as class components.
First let’s convert ES6’s TestC class to a function component:
import React from 'react';
const TestC = (props) => {
console.log(`Rendering TestC :` props)
return (
<div>
{props.count}
</div>
)
}
export default TestC;
// App.js
<TestC count={5} />
Copy the code
When the above code is first loaded, the console output is:
Again, we can open the Chrome debug tool, click the React TAB and select the TestC component:
We can see that the parameter value of this component is 5. Let’s change the value to 45, and the browser outputs this
The output shows that the component has been rerendered even though the count value remains the same, 45.
Since function components also have the problem of useless rendering, how can we optimize them?
3. Solution: use react.memo ()
React.memo(…) This is a new attribute introduced in React V16.6. It acts like the React.pureComponent and controls rerendering of function components. React.memo(…) This is the function component’s React.PureComponent.
How to use React. Memo (…) ?
React. Memo is easy to use, assuming you have the following function components:
const Funcomponent = ()=> {
return (
<div>
Hiya!! I am a Funtional component
</div>
)
}
Copy the code
All we need to do is pass the Funcomponent above as an argument to React. Memo:
const Funcomponent = ()=> {
return (
<div>
Hiya!! I am a Funtional component
</div>
)
}
const MemodFuncComponent = React.memo(FunComponent)
Copy the code
Memo returns a Purified component, MemoFuncComponent, which will be rendered in JSX tags. When a component’s props and state change, React will check whether the former props and state are the same as the next one. If so, the component will not be rendered. If not, the component will be re-rendered.
Now let’s optimize the TestC component using React. Memo:
let TestC = (props) => {
console.log('Rendering TestC :', props)
return (
<div>
{ props.count }
</>
)
}
TestC = React.memo(TestC);
Copy the code
Open the browser and reload our application. Then open the Chrome debugger, click the React TAB, and select the
component.
Then edit the props value and change the count to 89. We should see our application re-rendered:
Then repeat to set count to 89:
This is the React. Memo (…). This function is awesome!
The one before us didn’t use React. Memo (…) In the example, the repeated setting of count causes the component to rerender. However, when we use React. Memo, the component will not be rerendered as long as the value passed in remains the same.
High order Component (HOC)
Higher-order functions, functions that can be passed functions as arguments, such as map,sort,reduce. A higher-order component is a component that wraps another component.
- Props Proxy
- Inheritance Inversion
Immutable.js
Because the data is immutable, you can avoid the problem of passing values by reference, but it’s also troublesome
Stateless component
Using stateless components to receive props only from the parent can improve the rendering performance of the component
const HelloWorld = (props) => <div>{props.name}</div>ReactDOM.render(<HelloWorld name="HelloWorld" />,App)Copy the code
The value of componentWillReceiveProps of props
NextProps, not this.props
Bind function
By default, the bind function has an event parameter, but this parameter is after the given parameter
handleClockClick (id, e) {console.log(id,e)}<button onClick={this.handleClockClick.bind(this, 2)}>Clock</button>Copy the code
In the ES6 class, the function this does not point to an object by default
Access to elements
- This.getdomnode was removed in earlier versions, and now set ref= XXX, then use this.refs.xxx to access the DOM element
- Ref can be assigned to either a string or a function. Strings can only be assigned to class components, functions to DOM elements, and refs cannot be assigned to pure function components. Old versions of DOM elements can use ref, but React is not recommended.
ref="test"// this.refs.test access ref={test => this.test = test} // this. Test accessCopy the code
Composition VS Inheritance
React recommends using composition instead of inheritance. Composition is more intuitive in the UI, and the code looks easier. It is more in line with our understanding and the React Component-base feature.
The default value is true when only the property name is written
<MyComponent isStock/>// isStock defaulttrueCopy the code
createPortal
- The method to mount the child node to a component other than the parent, used in the render method, cannot be mounted to the parent component because the parent component is not rendered and cannot get the DOM
- The React DOM tree is still on this component, including event bubbles and things like that
|
Error boundary
ComponentDidCatch Error bounds that define a parent component for the component that catches the error and provides the UI to fall back on
- usage
|
- Error events that cannot be caught handle asynchronous code (such as setTimeout or requestAnimationFrame callbacks) the server side renders errors thrown by the error boundary itself (rather than its children)
High-level components are functions
- You should not modify the properties of the original component in a higher-order component
- Wrap a component with a function, returning a new component
- Switch different data sources for the component
- Showcase component, using the getData (Showcase, data) function package, obtain different data
- Do not use higher-order components in Render because each time a component is mounted, an instance of the higher-order component is retrieved
- hoistNonReactStatic Copy the static methods of the original component into the wrapped component
Container components
- Handles data subscription and status management
- Higher-order components are parameterized container components
rander prop
The title is the same, and the higher-order components are used to render the title to different components
Use the Web Component in React
One thing to note at this point is that you should use class, not className, for the Web Component
The lable for
For is a reserved word in JS, so use htmlFor instead
Style property
Browser suffixes, with the exception of MS, should begin with a capital letter. That’s why WebkitTransition has a capital W.
|
Use React16 below IE11
React16 relies on the collection types Map and Set, and requires a polyfill, such as core-js and Babel-Polyfill, in browsers that do not provide native support
Use core-JS support
|
ComponentDidMount Requests server data
When componentDidMount requests server data and uses setState, note that componentWillUnmount should be removed
Pass component props using the new ES6 feature
const {data, type} = this.state; // Demo data={data}type= {type}/> // es6 method <Demo {... {data,type}} / >Copy the code
3. Use ES6 REST parameters (in the form… Passes a variable number of props
Const Demo = ({prop1, prop2,... RestProps}) => (<div>{restProps. Text}</div>) // Demo < prop1={XXX} prop2={XXX} text={XXX}/>Copy the code
Other uses of setState
Const {data} = this.state; this.setState({ data: {... data, key: 1 } }); This.setstate (({data}) => ({data: {... data, key: 1 } })); This.setstate ((state, props) => {return { counter: state.counter + props.step };
});Copy the code
5. React performance optimization
// React performance optimization can be done in a variety of ways. One of the common ways is to use the life cycle function shouldComponentUpdate to determine certain values or properties that control whether a component is rerender. // It's easier to handle strings, numbers, or basic objects or arrays // It's harder to handle nested objects or arrays. For this // it is recommended to use the isEqual of lodash(or any similar library) to determine nested arrays or objects shouldComponentUpdate(nextProps, nextState) {if (_.isEqual(nextState.columns, this.state.columns)) return false;
return true;
}Copy the code
React Advanced – Tips (28 videos) link
Introduce some advanced knowledge points of React, some practical skills of development, some tool libraries, etc.
The video can be updated at www.qiuzhi99.com/
React Advanced – Tips
React Tips #1 How to deploy a React app with netlify Cloud Service
React #2 Deploy the React app to GitHub Pages 18 “05:34”
#3 React-Router Tutorial Part 1 51 “10:29”
#4 React-Router Tutorial Part 2 11 “07:39”
React Advanced #5 best way to write stateless components
#6 Fragment 14 “Pro” “02:36”
React Advanced #7 Context 9 “03:58”
React Advanced Upgrade #8 advanced Component 14 “Pro” “02:51”
React Advanced #9 Powerful, cool and fun Web IDE (mouse click to generate code, reduce development time by N times)
React Advanced #10 Refactoring code with higher-order components
1 “Pro” “04:30” 1 “Pro” “04:30”
React Advancements #12 Correct way to return multiple components
React Advanced upgrade #13 Netlifyctl deploy front-end application 2 “06:49”
React Advance raise #14 defaultProps and type check PropTypes part 14 “06:37”
PropTypes Part 2 “Pro”
#16 React Props instead of HOC
React Advanced #17 Error boundary and lifecycle function componentDidCatch 9 “Pro” “11:45”
React Upgrade #18 to 16.3 “02:37”
9 “03:50”
React 16.3 new Context API 1 “06:50”
#21 React 16.3 New Context API – Practice 3 “Pro” “09:19”
Change the Redux Context API to the React 16.3 Context API
React Advanced #23 Objects, arrays, mutable data 9 “Pro”
#24 React.Children API and props. Children 解 视 4 “Pro” “06:06”
#25. Styled – Components 5 “Pro” “04:56”
#26. Styled – Components (Practice) “Pro”
You should use redux-form 12 “Pro” “06:40”
Redux-form (Practice) 7 “Pro”
Learning materials
data
Doc.react-china.org/ translated official documents, you must read the documents several times to learn technology
React little book strongly recommend, from the shallow to the deep, step by step
Reactpatterns.com/ Because the React API itself is relatively simple, close to native. A series of patterns are generated through component changes
Github.com/CompuIves/c… React Online editor, easy to share your React projects
devhints.io/react
Js. Coach find js package website
video
Basic free, premium charged egghead. IO