React【Context_作用、函数组件订阅Context、Fragments 、错误边界_概念 、错误边界_应用、Refs & DOM】(四)

目录

Context_作用

函数组件订阅Context

Fragments

 错误边界_概念

 错误边界_应用

Refs & DOM


Context_作用

 React组件中数据是通过 props 属性自上而下(由父及子)进行传递的,但是有的时候中间的一些组件可能并不需要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'}}>
       NabBar的内容
        <UserInfo user={this.props.user}/>
        </div>
   )
 }
}

//UserInfo.js
import React, { Component } from 'react'
export default class UserInfo extends
Component {
  render() {
    return (
      <div>你好,欢迎 {this.props.user.account}</div>
   )
 }
}

Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据传递的方法。
 

何时使用 Context

如果我们要在组件树中去共享某些数据,并且要避免通过中间元素传递 props,则可以使用Context来实现。

Context_应用


 1、创建Context对象

React.createContext(defaultValue)

const MyContext = React.createContext(defaultValue);

2、 Context 的 Provider 组件

Contenxt的Provider组件用来提供其它组件要共享的数据。
设置 value 属性来设置要共享的数据。

<MyContext.Provider value={/* 某个值 */}>

3、Context 的 Provider 组件

Contenxt的Provider组件用来提供其它组件要共享的数据。
设置 value 属性来设置要共享的数据。

<MyContext.Provider value={/* 某个值 */}>

提示:我们把要使用共享数据的组件称为 消费组件 。

 Class.contextType

为组件类添加 contextType 属性,从而获取Context对象。

MyClass.contextType = MyContext;

提示:
挂载在 class 上的 contextType 属性会被重赋值为一个由
React.createContext() 创建的 Context 对象。这能让你使用 this.context 来消费最近 Context 上的那个值。
你可以在任何生命周期中访问到它,包括 render 函数中。

//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: '小童',account: 'xiaotong' } }
   }
    
    render() {
        return <div>
             {/* 使用Provider组件提供数据 */}
            <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'}}>
        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>你好,欢迎 {this.context.account}</div>
   )
 }
}
//设置类的contentType属性,从而获取context对象
UserInfo.contextType=MyContext

函数组件订阅Context


 

 Context.Consumer

<MyContext.Consumer>
 {value => /* 基于 context 值进行渲染*/}
</MyContext.Consumer>
//ContextTest.js
render() {
        return <div>
           {/* 使用Provider组件提供数据 */}
            <MyContext.Provider value= {this.state.user }>
                <NavBar />
                <MyContext.Consumer>
                   {value=><div>
                        <h3>函数组件</h3>
                       获取到的账户:{value.account}
                        </div>}
                    
                </MyContext.Consumer>
              
            </MyContext.Provider>
            
        </div>
   }

Context更新
当 Provider 的 value 值发生变化时,它内部的所有消费组件都会重新渲染。
 

//ContextTest.js
render() {
        return <div>
            <button onClick= {()=>this.setState({user:{name:"xiaotong",account:'xiaotong123'}})}>更新user</button>
           {/* 使用Provider组件提供数据 */}
            <MyContext.Provider value={this.state.user }>
                <NavBar />
                <MyContext.Consumer>
                   {value=><div>
                        <h3>函数组件</h3>
                       获取到的账户:{value.account}
                        </div>}
                    
                </MyContext.Consumer>
              
            </MyContext.Provider>
            
        </div>
   }

 提示:消费组件是否重新渲染不受shouldComponentUpdate的控制。
其父组件使用shouldComponentUpdate停止了渲染或者消费组件本身使用shouldComponentUpdate停止渲染,也不影响消费组件的继续更新。
 

//NavBar.js
export default class NabBar extends
Component {
  shouldComponentUpdate(){
      //当前这个非消费组件会停止更新渲染,但是它的子组件UserInfo是Context的消费组件,还会继续更新
    return false
 }
  render() {
    console.log('navbar')
    return (
      <div style= {
   
   {height:'50px',background:'#ccc',display:'flex',justifyContent:'space-around',alignItems:'center'}}>
       NabBar的内容
        <UserInfo />
        
        </div>
   )
 }
}

//UserInfo.js
import React, { Component } from 'react'
import MyContext from './MyContext'
export default class UserInfo extends
Component {
    shouldComponentUpdate() {
        //虽然返回了false,但是context的值发生变化了,我还是要重新渲染的
        return false
   }
    render() {
        return (
            <div>你好,欢迎{this.context.account}</div>
       )
   }
}
UserInfo.contextType = MyContext

Fragments

 场景一:

render() {
    return (
      <p></p>
      <p></p>
   )
 }

提示: react当中,组件的界面只能有一个根标签。

 场景二:

render() {
    return (
        // 最外层的这个div可能根本不需要,不想让它渲染到页面上
        <div>
             <p></p><p></p>
        </div>
    
   )
 }

Fragments 允许你将子元素包裹在一起,而无需向 DOM 添加额外节点。
 

render() {
    return (
   <React.Fragment>
      <p></p>
      <p></p>
   </React.Fragment>
   )
 }

最终页面渲染结果:

1、Fragments 短语法

使用 <></> 代替 <React.Fragment></React.Fragment>

render() {
    return (
   <>
      <p></p>
      <p></p>
   </>
   )
 }

提示:
因为Fragments最终不会被渲染为DOM,所以不要在Framents上面绑定事件或者设置一些其它属性,目前只支持设置key属性。

 错误边界_概念

 通常某一个组件中发生的错误会导致整个应用崩溃,页面一片空白。

//App.js
render() {
    return (
      <>
        <ContextTest />
        <SomethingWrong />
      </>
   )
 }

//SomethingWrong.js
export default class SomethingWrong extends
Component {
  constructor(){
     // 未调用super,则会抛出错误
 }  
  render() {
    return (
      <div>
        <Child/>
      </div>
   )
 }
}

如果我们想让未出现错误的组件还能继续渲染,则可以使用 错误边界
错误边界 是一种 React 组件。
错误边界 可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它可以渲染出备用 UI。
错误边界 在渲染期间、生命周期方法和整个子组件树的构造函数中捕获错误。

 提示: 错误边界无法捕获以下场景中产生的错误:
1、事件处理
2、异步代码(例如 setTimeout 或 requestAnimationFrame 回调函数)

3、它自身抛出来的错误(并非它的子组件)

 错误边界_应用

1、 定义一个错误边界的组件
class 组件中定义了 static getDerivedStateFromError()componentDidCatch() 这两个生命周期方法中的任意一个(或两个)时,那么这个组件就变成一个错误边界的组件。

import React, { Component } from 'react'
export default class ErrorBoundary extends
Component {
    constructor() {
        super()
        this.state = { }
   }
    componentDidCatch(error, errorInfo) {
        // 捕获到子组件树当中发生的错误时调用
        this.setState({
          error: error,
          errorInfo: errorInfo
       })
        
     }
    render() {
        return (
           this.state.errorInfo ? <div>奥,糟糕!!发生了一些错误:
               错误信息如下:<br />
               {this.state.error && this.state.error.toString()}
            <br />
           {this.state.errorInfo.componentStack}
              
            </div> : this.props.children
       )
   }
}

错误边界的使用
 

//App.js
render() {
    return (
      <>
        <ContextTest />
         {/* 使用错误边界组件包裹的组件树,发生的错误都会被这个错误边界捕获 */}
        <ErrorBoundary>
          <SomethingWrong />
        </ErrorBoundary>
      </>
   )
 }

错误边界无法捕获的错误


 

 错误边界无法捕获的错误,比如事件处理,异步操作。可以使用原生js支持的一些方法去捕获。

 try/catch

onClick=()=>{
    try{
        //使用一个未定义的变量a,会报错
       console.log(a)
   }catch(e){
        console.log(e)
        this.setState({hasError:true})
   }
    
 }
  render() {
    return (
      <div>
        <button onClick={this.onClick}>点击</button>
       {this.state.hasError?<div>出现错误了</div>:null}
      </div>
   )
 }

window.onerror

window.onerror可以捕捉语法错误,也可以捕捉运行时错误,只要在当前window执行的Js脚本出错都会捕捉到。
 

window.onerror=function(err){
  console.log(err)
}

Refs & DOM

 Refs 提供了一种方式,允许我们访问DOM 元素。

<div ref={ref}></div>

创建 Refs
使用 React.createRef() 创建的。
通常将 Refs 分配给实例属性,以便可以在整个组件中引用它们。
 

constructor(props) {
    super(props);
    this.myRef = React.createRef();
 }

使用Refs
给对应的React 元素设置 ref 属性,则相当于使用 ref 去存储DOM 节点的引用。
 

render() {
    return <input ref={this.myRef} />;
 }

访问Refs
ref 被传递给 render 中的元素时,对该节点的引用可以在 ref current 属性中被访问。
 

componentDidMount(){
    const node = this.myRef.current;
    node.focus()
 }

提示:
React 会在组件挂载时给 current 属性传入 DOM 元素,并在组件卸载时传入 null 值。

ref 会在 componentDidMount componentDidUpdate
生命周期钩子触发前更新。

猜你喜欢

转载自blog.csdn.net/m0_58719994/article/details/133162794
今日推荐