The use of the setState
The setState() function is used to update the state of a component, written both object and functional.
/ / object type
this.setState({
count: this.state.count + 1
})
/ / function type
this.setState((state, props) = > {
count: state.count + 1
})
Copy the code
Functional writing can receive the state and props of the current component directly from the parameters, making it easier to handle the state. Either way, the second argument to setState() can receive a callback function.
this.setState({
count: this.state.count + 1
}, () = > { // The callback function
console.log(this.state.count)
})
Copy the code
SetState () updates the state asynchronously, and the callback is triggered when the state change is complete. That is, if you print a state value directly after the setState() call, you are likely to get the same value as before.
Hooks
Hooks are functionality for functional components that began in version 16.8. Functional components do not have this, so they cannot operate on state, refs, and lifecycle Hooks, which are fixed by Hooks. In practice, it’s not as comfortable to write as a class component, so stick with the utility class component.
State Hook
export default function Demo() {
const [name, setName] = React.useState('zidu')
changeName() {
/ / operating state
setName('CallbackZidu')}return (
<div>
<h2>User name: {name}</h2>
<button onClick={changeName}>The name</button>
</div>)}Copy the code
Use react.usestate () to create a state. The example uses array destructuring assignment syntax. Name is the name of the state, and setName is the function that operates on it. If you have multiple states to maintain, use react.usestate () multiple times to create those states. Of course, you can also create a single state of the object type to manage them all, but there is a big catch.
The setXxx function obtained from react.usestate () handles state changes differently than setState(). The setState() function allows you to change the value of only some of the states. That is, the setState() function takes the returned object and merges it with the previous state. SetXxx, however, does not merge, but replace.
const [all, setAll] = React.useState({
name: 'zidu'.age: 27
})
setAll({
// The value of name is not changed, but the original value is still assigned, otherwise the name will not exist after the function completes.
name: all.name,
age: 28
})
Copy the code
Effect Hook
Effect Hook uses functions to simulate the life cycle of a component, but only three life cycles can be simulated, and it is a bit convoluted to distinguish the different life cycles.
React.useEffect(() = > {
console.log('Just pass a function that emulates the componentDidUpdate lifecycle hook')})Copy the code
If react.useEffect () only receives an arrow function as an argument, the arrow function is the componentDidUpdate lifecycle hook.
React.useEffect(() = > {
console.log('The second argument is an empty array, mimicking the componentDidUpdate lifecycle hook.')}, [])Copy the code
If the second argument received is an empty array, the arrow function is the componentDidMount lifecycle hook.
React.useEffect(() = > {
console.log('Array has elements that simulate life cycle hooks for componentDidUpdate and componentDidUpdate')
}, [name])
Copy the code
If the second argument received is not an empty array, then the arrow function is the componentDidMount lifecycle hook, and is fired as the componentDidUpdate lifecycle hook every time the value of the Name state changes.
React.useEffect(() = > {
// do something...
return () = > {
console.log('Returns an arrow function that simulates the componentWillUnmount lifecycle hook')
}
}, [name])
Copy the code
If the arrow function is returned in the first argument, the returned arrow function is the componentWillUnmount lifecycle hook.
Refs Hook
Refs hooks are used in the same way as react.createref ().
export default function demo() {
// Create a Ref hook
const myRef = React.useRef()
function getText() {
alert(myRef.current.value)
}
return (
<div>
<input type="text" ref={myRef} /><br/>
</div>)}Copy the code
Component lazy loading
Lazy loading of components can avoid loading all the components that are not needed at the first time a page is opened. This will speed up page loading and components will not be loaded until they really need to be rendered.
Create component A:
export default class A extends Component {
render() {
return (
<div>
<h2>I am A</h2>
</div>)}}Copy the code
Create component B:
export default class B extends Component {
render() {
return (
<div>
<h2>I'm a B</h2>
</div>)}}Copy the code
Create a Loading component that says:
export default class Loading extends Component {
render() {
return (
<div>
<h2 style={{backgroundColor: 'orange'}} >Loding...</h2>
</div>)}}Copy the code
import React, { Component, lazy, Suspense } from 'react'
import {NavLink, Route} from 'react-router-dom'
// Synchronously load the Loading component
import Loading from './Loading'
// load A and B lazily
const A = lazy(() = > import('./A'))
const B = lazy(() = > import('./B'))
export default class Main extends Component {
render() {
return (
<div>
<ul>
<NavLink to="/a">Home</NavLink>
<NavLink to="/b">About</NavLink>
</ul>
<hr/>
<Suspense fallback={<Loading/>} ><Route path="/a" component={A} />
<Route path="/b" component={B} />
</Suspense>
</div>)}}Copy the code
The lazy() function is used to implement lazy loading of components, receiving a function that provides the component to be loaded, and the import() import function serves the same purpose as the keyword import. It is important to note that after lazy Loading is used, you must use
components to wrap lazy Loading components, and use the fallback attribute to specify the Loading component in the case of lazy Loading and failure, that is, the Loading component in the example. This component can only be loaded synchronously.
Fragment
is actually a placeholder component that looks like a component when coding but is ignored when rendering. For example, we usually wrap a
instead. It can also be used to replace unnecessary structures when traversing a render list.
import React, { Component, Fragment } from 'react'
export default class FragmentDemo extends Component {
render() {
return (
<Fragment>
<h2>The Fragment tag is discarded at compile time to prevent multiple components from nesting too many layers of divs</h2>
<h2>Fragment can receive a key attribute, which can be used during traversal to avoid creating too many outer elements</h2>
</Fragment>)}}Copy the code
PureComponent
Class components have been created by inheriting react.component. When multiple components are nested and the child component uses values passed by the parent component through props, if the parent component changes state, the child component will be rendered as the parent component renders regardless of whether the state used by the child component changes.
import React, { Component } from 'react'
export default class A extends Component {
state = {
name: 'zidu'.age: 27
}
changeName = () = > {
this.setState({
name: 'CallbackZidu'})}render() {
console.log('Component A renders')
const {name, age} = this.state
return (
<div>
<h2>Component A</h2>
<h2>Name: {name}</h2>
<br/>
<button onClick={this.changeName}>The name</button>
<hr/>
<B age={age}/>
</div>)}}class B extends Component {
render() {
console.log('Component B has rendered')
return (
<div>
<h2>The component B</h2>
<h2>Age: {this. Props. Age}</h2>
</div>)}}Copy the code
It is obvious that passive rendering of the subcomponent is not necessary, so you can avoid this by having the subcomponent inherit the React.PureComponent. The React.PurComponent actually overrides the shouldComponentUpdate lifecycle hook to internally determine if state and props have changed to allow the component to perform state updates. For convenience, all components can inherit from React.PurComponent instead of react.component.react.component.react.component.react.purComponent.
RenderProps
The name is a bit fancy and confusing, but it’s actually the same Slot technology as Vue’s Slot, just with a different syntax. Look directly at the example:
import React, { PureComponent } from 'react'
import OtherComponent from '.. /OtherComponent'
export default class RenderPropsDemo extends PureComponent {
render() {
return (
<div>
<h2>This is the RenderPropsDemo component</h2>{/* Return the component to be inserted by passing a function */}<A render={()= > <OtherComponent/>} / ></div>)}}/** * use this.props. Render () to set the location in JSX to insert other DOM */
class A extends PureComponent {
render() {
return (
<div>
<h2>This is component A</h2>
{this.props.render()}
</div>)}}Copy the code
Just say this.props. Render () where you want to insert another component, and the component will appear there. Of course the render name on this props can be changed at will, but it is usually called this. To insert a component, pass an arrow function on props to return the label for the component to be inserted.
Context
Context can be used for communication between parent and child components. Context can be used for communication between sibling components. Context can also be used for communication between parent and child components.
For example, if A wants to pass some data to C, create A Context using react.createcontext ().
import React, { Component } from 'react'
import './index.css'
// Create a Context
const NameContext = React.createContext()
export default class ContextDemo extends Component {
state = {
name: 'zidu'.age: 27
}
render() {
const {name, age} = this.state
return (
<div className="parent">
<h2>A component</h2>
<h2>Name: {name}</h2>{/* Use Provider to include next-level components */}<NameContext.Provider value={name}>
<B />
</NameContext.Provider>
</div>)}}class B extends Component {
render() {
return (
<div className="child">
<h2>B component</h2>
<h2>Show something to play with</h2>
<C/>
</div>)}}function C() {
return (
<div className="grand">
<h2>C components</h2>
<h2>Use the Consumer tag to receive the name: {/* The arrow function argument in Consumer is the data passed from the A component */}<NameContext.Consumer>
{
value => {
return value.name
}
}
</NameContext.Consumer>
</h2>
<D/>
</div>)}Copy the code
The C component can also be received without the
tag, which is easier to use programmatically:
class C extends Component {
// Declare the Context to be used
static contextType = NameContext
render() {
return (
<div className="grand-grand">
<h2>C components</h2>
<h2>Receive name with contextType: {this.context.name}</h2>
</div>)}}Copy the code
Context is usually used when encapsulating components, but less often when writing business. Communication between grandparent and grandchild components is either Redux or publish-subscribe, which is more comfortable to use than Context.
Error boundary
The child component may fail to render due to the failure of requesting data or receiving data that is not in the agreed format. In this case, the exception will be passed out and the entire page will fail to render with an error message. Error boundaries limit rendering errors of child components to a certain range and replace the error messages with specific content.
For example, component B is used in component A. In order to avoid the above situation, the following measures can be taken:
state = {
childLoadSuccess: true
}
// Specific function, just remember it
static getDerivedStateFromError(error) {
return {
childLoadSuccess: false}}render() {
return (
<div>
{
this.state.childLoadSuccess ? <B/> : <h4>Component B is abnormal</h4>
}
</div>)}Copy the code
Define a state, childLoadSuccess, to indicate whether component B has rendered incorrectly. When component B renders incorrectly, the getDerivedStateFromError function is raised. Inside the function, an object is returned to change childLoadSuccess. This allows the state of childLoadSuccess to determine whether to render the B component or the standby component or information when the A component is rendered. Also available is a lifecycle hook componentDidCatch, which is fired when an exception occurs and where you can submit an error report to the server.