Table of Contents
Context_role
Function component subscribes to Context
Fragments
Error Boundary_Concept
Error Boundary_Application
Refs & DOM
Context_role
Data in React components is passed from top to bottom (from parent to child) through the props attribute, but sometimes some components in the middle may not need the value of props.
//App.js return ( <div> <ContextTest /> </div> );
//ContextTest.js import React from 'react' import NavBar from './NavBar' export default class ContextTest extends React.Component{ constructor(props){ super(props) this.state={user:{name:'小子',account:'baizhan'}} } render(){ return <div> <NavBar user={this.state.user}/> </div> } }
//NavBar.js import React, { Component } from 'react' import UserInfo from './UserInfo' export default class NabBar extends Component { render() { return ( <div style= {<!-- -->{height:'50px',background:'#ccc',display:'flex',justifyContent:'space-around',alignItems: 'center'}}> Contents of NabBar <UserInfo user={this.props.user}/> </div> ) } }
//UserInfo.js import React, { Component } from 'react' export default class UserInfo extends Component { render() { return ( <div>Hello and welcome {this.props.user.account}</div> ) } }
Context provides a way to pass data between component trees without manually adding props for each layer of components.
When to use Context
If we want to share some data in the component tree and avoid passing props through intermediate elements, we can use Context to achieve this.
Context_Application
1. Create Context object
React.createContext(defaultValue)
const MyContext = React.createContext(defaultValue);
2. Provider component of Context
The Provider component of Contentxt is used to provide data to be shared by other components.
Set the value attribute to set the data to be shared.
<MyContext.Provider value={/* a certain value */}>
3. Provider component of Context
The Provider component of Contentxt is used to provide data to be shared by other components.
Set the value attribute to set the data to be shared.
<MyContext.Provider value={/* a certain value */}>
Tip: We call components that use shared data consuming components.
Class.contextType
Add the contextType attribute to the component class to obtain the Context object.
MyClass.contextType = MyContext;
hint:
The contextType attribute mounted on class will be reassigned to a
The Context object created by React.createContext() . This allows you to use this.context to consume the value from the most recent Context.
You can access it in any life cycle, including the render function.
//MyContext.js import React from "react"; export default React.createContext({name:'',account:'xxx'})
//ContextTest.js import React from 'react' import MyContext from './MyContext' import NavBar from './NavBar' export default class ContextTest extends React.Component { constructor(props) { super(props) this.state = { user: { name: 'xiaotong',account: 'xiaotong' } } } render() { return <div> {/* Use Provider component to provide data */} <MyContext.Provider value= {this.state.user}> <NavBar /> </MyContext.Provider> </div> } }
//NabBar.js import React, { Component } from 'react' import UserInfo from './UserInfo' export default class NabBar extends Component { render() { return ( <div style= {<!-- -->{height:'50px',background:'#ccc',display:'flex',justifyContent:'space-around',alignItems: 'center'}}> Contents of NabBar <UserInfo /> </div> ) } }
//UserInfo.js import React, { Component } from 'react' import MyContext from './MyContext' export default class UserInfo extends Component { render() { console.log(this.context) return ( <div>Hello and welcome {this.context.account}</div> ) } } //Set the contentType attribute of the class to obtain the context object UserInfo.contextType=MyContext
Function component subscribes to Context
Context.Consumer
<MyContext.Consumer> {value => /* Render based on context value*/} </MyContext.Consumer>
//ContextTest.js render() { return <div> {/* Use Provider component to provide data */} <MyContext.Provider value= {this.state.user}> <NavBar /> <MyContext.Consumer> {value=><div> <h3>Function component</h3> Obtained account: {value.account} </div>} </MyContext.Consumer> </MyContext.Provider> </div> }
Context update
When the Provider’s value changes, all consuming components inside it will be re-rendered.
//ContextTest.js render() { return <div> <button onClick= {()=>this.setState({user:{name:"xiaotong",account:'xiaotong123'}})}>Update user</button> {/* Use Provider component to provide data */} <MyContext.Provider value={this.state.user}> <NavBar /> <MyContext.Consumer> {value=><div> <h3>Function component</h3> Obtained account: {value.account} </div>} </MyContext.Consumer> </MyContext.Provider> </div> }
Tip: Whether the consuming component is re-rendered is not controlled by shouldComponentUpdate.
Even if its parent component uses shouldComponentUpdate to stop rendering or the consuming component itself uses shouldComponentUpdate to stop rendering, it will not affect the continued updating of consuming components.
//NavBar.js export default class NabBar extends Component { shouldComponentUpdate(){ //The current non-consuming component will stop updating and rendering, but its sub-component UserInfo is the consuming component of Context and will continue to be updated. return false } render() { console.log('navbar') return ( <div style= {<!-- -->{height:'50px',background:'#ccc',display:'flex',justifyContent:'space-around',alignItems: 'center'}}> Contents of NabBar <UserInfo /> </div> ) } }
//UserInfo.js import React, { Component } from 'react' import MyContext from './MyContext' export default class UserInfo extends Component { shouldComponentUpdate() { //Although false is returned, the value of context has changed, so I still have to re-render it. return false } render() { return ( <div>Hello, welcome {this.context.account}</div> ) } } UserInfo.contextType = MyContext
Fragments
Scene 1:
render() { return ( <p></p> <p></p> ) }
Tip: In react, the component interface can only have one root tag.
Scene 2:
render() { return ( //The outermost div may not be needed at all, and we don't want it to be rendered on the page. <div> <p></p><p></p> </div> ) }
Fragments allow you to wrap child elements together without adding extra nodes to the DOM.
render() { return ( <React.Fragment> <p></p> <p></p> </React.Fragment> ) }
Final page rendering result:
1. Fragments short syntax
Use <>> instead of
render() { return ( <> <p></p> <p></p> </> ) }
hint:
Because Fragments will not be rendered into DOM in the end, do not bind events or set some other attributes on Framents. Currently, only setting the key attribute is supported.
Error Boundary_Concept
Usually an error in one component will cause the entire application to crash and the page to go blank.
//App.js render() { return ( <> <ContextTest /> <SomethingWrong /> </> ) }
//SomethingWrong.js export default class SomethingWrong extends Component { constructor(){ // If super is not called, an error will be thrown } render() { return ( <div> <Child/> </div> ) } }
If we want components that do not have errors to continue rendering, we can use error boundaries.
ErrorBounds is a React component.
Error Bounds can catch and print JavaScript errors that occur anywhere in its child component tree, and it can render out an alternate UI.
Error Bounds Catch errors during rendering, in lifecycle methods, and in constructors throughout the subcomponent tree.
Tip: Error boundaries cannot capture errors generated in the following scenarios:
1. Event handling
2. Asynchronous code (such as setTimeout or requestAnimationFrame callback function)3. Errors thrown by itself (not its subcomponents)
Error Boundary_Application
1. Define a component with error boundaries
When either (or both) of the two life cycle methods static getDerivedStateFromError() or componentDidCatch() is defined in a class component, the component becomes A component with error boundaries.
import React, { Component } from 'react' export default class ErrorBoundary extends Component { constructor() { super() this.state = { } } componentDidCatch(error, errorInfo) { // Called when an error occurs in the subcomponent tree is captured this.setState({ error: error, errorInfo: errorInfo }) } render() { return ( this.state.errorInfo ? <div>Oh, crap! ! Some errors occurred: The error message is as follows:<br /> {this.state.error & amp; & amp; this.state.error.toString()} <br /> {this.state.errorInfo.componentStack} </div> : this.props.children ) } }
Use of error boundaries
//App.js render() { return ( <> <ContextTest /> {/* Use the component tree wrapped by the error boundary component, and any errors that occur will be captured by this error boundary */} <ErrorBoundary> <SomethingWrong /> </ErrorBoundary> </> ) }
Errors that cannot be caught by error boundaries
Errors that cannot be captured by error boundaries, such as event processing and asynchronous operations. You can use some methods supported by native js to capture.
try/catch
onClick=()=>{ try{ //Using an undefined variable a will report an error console.log(a) }catch(e){ console.log(e) this.setState({hasError:true}) } } render() { return ( <div> <button onClick={this.onClick}>Click</button> {this.state.hasError?<div>An error occurred</div>:null} </div> ) }
window.onerror
window.onerror can capture syntax errors and runtime errors. As long as there is an error in the JS script executed in the current window, it will be captured.
window.onerror=function(err){ console.log(err) }
Refs & amp; DOM
Refs provide a way to access DOM elements.
<div ref={ref}></div>
Create Refs
Created using React.createRef().
Refs are usually assigned to instance properties so that they can be referenced throughout the component.
constructor(props) { super(props); this.myRef = React.createRef(); }
Use Refs
Setting the ref attribute to the corresponding React element is equivalent to using ref to store references to DOM nodes.
render() { return <input ref={this.myRef} />; }
VisitRefs
When ref is passed to an element in render, a reference to that node can be found in ref ‘s current attribute was visited.
componentDidMount(){ const node = this.myRef.current; node.focus() }
hint:
React will pass a DOM element to the current property when the component is mounted, and pass a null value when the component is unmounted.ref will be called in componentDidMount or componentDidUpdate
Update before life cycle hook is triggered.