React learning notes 7: precautions for the use of react

1. setState

Two ways of writing setState update state

Method 1: setState(stateChange, [callback]) ---- object type setState

  • stateChange is a state change object (this object can reflect the state change)
  • Callback is an optional callback function. It is called only after the status is updated and the interface is updated (after render is called)

Method 2: setState(updater, [callback]) ---- functional setState

  • updater is a function that returns a stateChange object
  • The updater can receive state and props
  • Callback is an optional callback function. It is called only after the status is updated and the interface is updated (after render is called).

summary

Object style setState is the abbreviation of function style setState (syntax sugar)

Use principle

The following principles are only suggestive and not mandatory

  1. If the new state does not depend on the original state = = = > use object mode
  2. If the new state depends on the original state = = = > use function mode
  3. If you need to get the latest state data after setState() is executed, you need to read it in the second callback function

setState synchronous VS asynchronous problem

  • setState is "asynchronous" only in synthetic events and hook functions, and synchronous in native events and settimeouts.

    • Composite events: onClick and other composite events of react in the component belong to its user-defined composite events
    • Native events: for example, the native events in dom added through addeventListener
  • The "asynchrony" of setState does not mean that it is implemented internally by asynchronous code. In fact, the process and code executed by itself are synchronous, but the calling sequence of synthetic events and hook functions is updated before, so it is impossible to get the updated value immediately in synthetic events and hook functions, in the form of so-called "asynchrony", Of course, you can get the updated result through the callback in the second parameter setState (partial state, callback).

  • The batch update optimization of setState is also based on "asynchrony" (synthetic event and hook function). Batch update will not be carried out in the native event and setTimeout. In "asynchrony", if the same value is setState multiple times, the batch update strategy of setState will overwrite it and take the last execution. If multiple different values of setState are updated at the same time, they will be consolidated and updated in batch.

  • As can be seen from the above figure, in react, setState updates the state through a queue mechanism. When setState is executed, the state to be updated will be merged and put into the state queue, instead of updating this immediately State. When the component can be updated, the queue mechanism will update the state in batches efficiently.
import React, { Component } from 'react'

export default class Demo extends Component {

	state = {
		count: 0
	}

	add = () => {
		//Method 1: object type setState
		// //1. Get the original count value
		// const { count } = this.state
		// //2. Update status
		// this.setState({ count: count + 1 }, () => {
		// 	console.log(this.state.count);
		// })
		// //If setState is used immediately after updating the data, there will be problems
		// //console.log('Get the latest count data as', this. State. Count)// 0 

		//Mode 2: functional setState
		this.setState(state => ({ count: state.count + 1 }))
	}

	render() {
		return (
			<div>
				<h1>The current summation is:{this.state.count}</h1>
				<button onClick={this.add}>Order me+1</button>
			</div>
		)
	}
}

2. lazyLoad (lazy load component)

lazyLoad of routing component

  • Step 1: dynamically load the routing component through the lazy function of React and the import() function = = = > the routing component code will be packaged separately

    const Login = lazy(()=>import('@/pages/Login'))
    
  • Step 2: specify a user-defined loading interface before loading the route packaging file through < suspend >

    <Suspense fallback={<h1>loading.....</h1>}>
            <Switch>
                <Route path="/xxx" component={Xxxx}/>
                <Redirect to="/login"/>
            </Switch>
        </Suspense>
    

3. Hooks

1. What is react hook / hooks?

  • Hook is a new feature / syntax added to React 16.8.0
  • You can use state and other React features in function components

2. Three commonly used hooks

  • State Hook: React.useState()
  • Effect Hook: React.useEffect()
  • Ref Hook: React.useRef()

2.1. State Hook

  • State Hook allows function components to have state and read and write state data
  • Syntax: const [XXX, setXXX] = react useState(initValue)
  • useState() description
    • Parameter: the specified value is cached internally during the first initialization
    • Return value: an array containing two elements. The first is the internal current status value, and the second is the function that updates the status value
  • setXxx() can be written in two ways
    • setXxx(newValue): the parameter is a non function value, which directly specifies a new status value and internally overwrites the original status value
    • SetXXX (value = > newvalue): the parameter is a function that receives the original status value and returns a new status value, which is used internally to overwrite the original status value

2.2. Effect Hook

  • Effect Hook allows you to perform side-effect operations in function components (used to simulate life cycle hooks in class components)

  • Side effect operation in React

    1. Send ajax request for data acquisition
    2. Set subscription / start timer
    3. Manually change the real DOM
  • Syntax and description

    useEffect(() => { 
              // Any operation with side effects can be performed here
              return () => { // Execute before component uninstallation
                // Do some finishing work here, such as clearing timer / unsubscribing, etc
              }
            }, [stateValue]) // If [] is specified, the callback function will only be executed after the first render()
    
  • explain

    useEffect Hook can be regarded as a combination of the following three functions

    • componentDidMount()
    • componentDidUpdate()
    • componentWillUnmount()

5. Ref Hook

  • Ref Hook can store / find tags or any other data in the function component

  • grammar

    const refContainer = useRef()
    
  • effect

    Save label object, function and react Createref()

4. Fragment (avoid extra marking)

  • summary

    • Using Fragment reduces the number of additional tags contained, which are only to meet the requirement of having a common parent in the React component.
    • When creating a new component, each component should have a single parent label. The parent cannot have two labels, so there should be a public label at the top. Therefore, additional labels are often added at the top of components
    • To include elements in a fragment. The fragment does not introduce any additional tags to the component, but it still provides parents for two adjacent tags, so the condition of having a single parent at the top level of the component is met
  • Usage

    <Fragment><Fragment>
    <></>
    
  • effect

    You don't have to have a real DOM root tag

  • The difference between < fragment > and < >

    • < > < / > syntax cannot accept key values or attributes, < fragment > can
    • Fragments declared using explicit < Fragment > syntax may have keys. key is the only attribute that can be passed to Fragment
import React, { Component, Fragment } from 'react'

export default class Demo extends Component {
	render() {
		return (
			<Fragment key={1}>
				<input type="text" />
				<input type="text" />
			</Fragment>
		)
	}
}

5. Context

Reasons for using Context

  • Sometimes you want to transfer data through the component tree, but you don't want to manually transfer attributes to components at each level, so context can transfer data across levels to the deep-seated components you want to transfer in the component tree

  • Sometimes, in order to pass a prop to component C in component B, component a needs to pass the parameters in the component twice before finally passing the prop in component A to component C

  • A communication mode between components, which is often used for communication between [ancestor component] and [descendant component]

Usage

  1. Create Context container object

    const XxxContext = React.createContext()  
    
  2. When rendering subcomponents, wrap xxxcontext Provider, which passes data to descendant components through the value attribute

    <xxxContext.Provider value={data}>
    		Subcomponents
    </xxxContext.Provider>
    
  3. The descendant component reads data

    //The first method: only applicable to class components 
    static contextType = xxxContext  // Claim receive context
    this.context // Read value data in context
    	  
    //The second way: both function components and class components can be used
    <xxxContext.Consumer>
         {
              value => ( // Value is the value data in the context
              What to display
              )
    	}
    </xxxContext.Consumer>
    

Examples

.parent{
	width: 500px;
	background-color: orange;
	padding: 8px;
}
.child{
	width: 100%;
	background-color: skyblue;
	padding: 8px;
}
.grand{
	width: 100%;
	background-color: gray;
	padding: 8px;
}
import React, { Component, createContext, useContext } from 'react'
import './index.css'

//Create Context object
const MyContext = createContext()
const { Provider, Consumer } = MyContext
export default class A extends Component {

	state = { username: 'Jack', age: 18 }

	render() {
		const { username, age } = this.state
		return (
			<div className="parent">
				<h3>I am A assembly</h3>
				<h4>My username is:{username}</h4>
				<Provider value={{ username, age }}>
					<B />
				</Provider>
			</div>
		)
	}
}

class B extends Component {
	render() {
		return (
			<div className="child">
				<h3>I am B assembly</h3>
				<C />
			</div>
		)
	}
}

// Mode 1
/* class C extends Component {
	//Claim receive context
	static contextType = MyContext
	render() {
		const {username,age} = this.context
		return (
			<div className="grand">
				<h3>I'm component C</h3>
				<h4>User name I received from component A: {username}, age {age} < / H4 >
			</div>
		)
	}
} */

//Mode 2
/* function C() {
	const contextData = useContext(MyContext)
	const { username, age } = contextData
	return (
		<div className="grand">
			<h3>I'm component C</h3>
			<h4>User name I received from component A: {username}, age = = {age} < / H4 >
		</div>
	)
} */

//Mode 3
function C() {
	return (
		<div className="grand">
			<h3>I am C assembly</h3>
			<h4>I from A User name received by component:
			<Consumer>
					{value => `${value.username},Age is ${value.age}`}
				</Consumer>
			</h4>
		</div>
	)
}

6. component optimization

summary

  • The key to the performance problems of web pages is the redraws and repaints of browsers (caused by Dom operations). The purpose of React virtual DOM is to reduce the redrawing and typesetting of the browser
  • There are two methods of component rendering: initial rendering and update rendering, and what we need to optimize is update rendering
  • shouldComponentUpdate (whether the component should be updated) must be called in the component update life cycle. shouldComponentUpdate returns true by default and must be updated. When we judge that the component does not need to be updated, shouldComponentUpdate can return false to achieve the optimization effect

Two problems of Component

  • As long as setState() is executed, even if the state data is not changed, the component will render() again = = > which is inefficient
  • Only the current component re renders (), it will automatically re render the sub components, even if the sub components do not use any data of the parent component = = > low efficiency

Efficient practices

  • Re render() only when the state or props data of the component changes

reason

  • shouldComponentUpdate() in Component always returns true. shouldComponentUpdate is a function that determines when the react Component can not be re rendered, but the default implementation of this function is to simply return a true. In other words, by default, the life cycle functions used, including the render function, will be called to re render each update.

solve

Mode 1

  • Override shouldComponentUpdate() method
  • Compare the old and new state or props data. If there is any change, it returns true. If there is no change, it returns false

Mode 2

  • Using PureComponent
  • PureComponent overrides shouldComponentUpdate(), and returns true only when the state or props data changes
  • matters needing attention
    • It only makes a shallow comparison between state and props data. If only the internal data of the data object changes, false is returned
    • Do not modify the state data directly, but generate new data
  • PureComponent is generally used to optimize in projects

Examples

  • style

    .parent{
    	background-color: orange;
    	padding: 10px;
    }
    .child{
    	background-color: gray;
    	margin-top: 30px;
    	padding: 10px;
    }
    
  • js code

    import React, { PureComponent } from 'react'
    import './index.css'
    
    export default class Parent extends PureComponent {
    
    	state = {
    		carName: "Benz c36",
    		stus: ['Xiao Zhang', 'petty thief', 'Xiao Wang']
    	}
    
    	addStu = () => {
    		const { stus } = this.state
    		this.setState({ stus: ['Xiao Liu', ...stus] })
    	}
    
    	changeCar = () => {
    		//this.setState({carName: 'Maybach'})
    
    		const obj = this.state
    		obj.carName = 'Maybach '
    		console.log(obj === this.state);
    		this.setState(obj)
    	}
    
    	/* shouldComponentUpdate(nextProps,nextState){
    		console.log("Current props and state===",this.props,this.state); / / current props and state
    		console.log("Next, the target props to be changed, target state = = ", nextprops, nextstate); / / next, the target props to be changed, target state
    		return !this.state.carName === nextState.carName
    	} */
    
    	render() {
    		console.log('Parent---render');
    		const { carName,stus } = this.state
    		return (
    			<div className="parent">
    				<h3>I am Parent assembly</h3>
    				{stus}&nbsp;
    				<span>My car name is:{carName}</span><br />
    				<button onClick={this.changeCar}>I'll change trains at</button>
    				<button onClick={this.addStu}>Add a Xiao Liu</button>
    				<Child carName="Alto" />
    			</div>
    		)
    	}
    }
    
    class Child extends PureComponent {
    
    	/* shouldComponentUpdate(nextProps,nextState){
    		console.log(this.props,this.state); //Current props and state
    		console.log(nextProps,nextState); //Next, the target props and target state to be changed
    		return !this.props.carName === nextProps.carName
    	} */
    
    	render() {
    		console.log('Child---render');
    		return (
    			<div className="child">
    				<h3>I am Child assembly</h3>
    				<span>The car I received was:{this.props.carName}</span>
    			</div>
    		)
    	}
    }
    

7. render props

How to dynamically transfer the structure (label) with content into the component?

  • In Vue, slot slot technology is used, that is, the structure < a > < B / > < / a > is passed in through the component label body
  • In React, there are two ways
    • Using children props: pass in the structure through the component label body
    • Use render props: the structure is passed in through the component tag attribute, and data can be carried. Generally, the render function attribute is used

children props

<A>
  <B>xxxx</B>
</A>
{this.props.children}

Problem: if component B needs the data in component A, = = > the above methods cannot be achieved

render props

<A render={(data) => <C data={data}></C>}></A>
  • Component A: {this. Props. Render (internal state data)}
  • Component C: read the data from component A and display {this.props.data}

8. Error boundary

summary

  • JavaScript exceptions that occur in the UI should not block the entire application. In order to solve this problem, React 16 introduces a new concept of "error boundary".

  • As a React component, the error boundary is used to catch JavaScript exceptions anywhere in the sub component tree, print these errors, and display the standby UI instead of crashing the component tree. The error boundary catches exceptions during rendering in the lifecycle method and in the constructor of its entire tree.

  • Error boundary: used to capture the errors of descendant components and render standby pages

  • The error boundary can only capture descendant component errors in the component tree. An error boundary cannot catch its own errors. If the error boundary fails when rendering the error message, the error is passed to the nearest error boundary of the previous layer

characteristic

  • Only errors resulting from the lifecycle of descendant components can be captured
  • It cannot capture the errors generated by its own components and the errors generated by other components in synthetic events and timers

Usage

getDerivedStateFromError with componentDidCatch

// The life cycle function will be triggered once the background component reports an error
static getDerivedStateFromError(error) {
    console.log(error);
    // Triggered before render
    // Return to new state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // Error in Statistics page. Send request to the background
    console.log(error, info);
}

Examples

  • Sub component code

    import React, { Component } from 'react'
    
    export default class Child extends Component {
    	state = {
    		users: [
    			{ id: '001', name: 'tom', age: 18 },
    			{ id: '002', name: 'jack', age: 19 },
    			{ id: '003', name: 'peiqi', age: 20 },
    		]
    		//Error boundary presentation data
    		// users:'abc'
    	}
    
    	render() {
    		return (
    			<div>
    				<h2>I am Child assembly</h2>
    				{
    					this.state.users.map((userObj) => {
    						return <h4 key={userObj.id}>{userObj.name}----{userObj.age}</h4>
    					})
    				}
    			</div>
    		)
    	}
    }
    
  • Parent component code

    import React, { Component } from 'react'
    import Child from './Child'
    
    export default class Parent extends Component {
    
    	state = {
    		hasError: '' //Used to identify whether the subcomponent generated an error
    	}
    
    	//When the child component of Parent reports an error, it will trigger the call getDerivedStateFromError and carry the error information
    	static getDerivedStateFromError(error) {
    		console.log('@@@', error);
    		return { hasError: error }
    	}
    
    	// React 16 will provide a built-in function componentDidCatch, which will be triggered if the render() function throws an error
    	// componentDidCatch is an info object that contains the error stack
    	componentDidCatch(error, info) {
    		console.log('Here, the statistics error is fed back to the server to notify the coder to make a correction bug Solution');
    		console.log('object error:>> ', error);
    		console.log('object info:>> ', info);
    		console.log('Error stack:>> ', info.componentStack);
    	}
    
    	render() {
    		return (
    			<div>
    				<h2>I am Parent assembly</h2>
    				{this.state.hasError ? <h2>The current network is unstable. Please try again later</h2> : <Child />}
    			</div>
    		)
    	}
    }
    

Tags: Front-end Optimize React Context

Posted by academy. on Mon, 18 Apr 2022 05:25:44 +0930