React [Context_function、関数コンポーネントのサブスクリプション コンテキスト、フラグメント、エラー境界概念、エラー境界_アプリケーション、Refs & DOM] (4)

目次

コンテキストの役割

関数コンポーネントが Context をサブスクライブする

断片

 エラー境界_概念

 エラー境界_アプリケーション

参照と DOM


コンテキストの役割

 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>
   )
 }
}

コンテキストは、コンポーネントの各レイヤーにプロップを手動で追加することなく、コンポーネント ツリー間でデータを受け渡す方法を提供します。
 

コンテキストを使用する場合

コンポーネント ツリー内の一部のデータを共有し、中間要素を介して props を渡すことを避けたい場合は、Context を使用できます。

コンテキスト_アプリケーション


 1.Contextオブジェクトの作成

React.createContext(defaultValue)

const MyContext = React.createContext(defaultValue);

2. Contextのプロバイダコンポーネント

Contentxt の Provider コンポーネントは、他のコンポーネントによって共有されるデータを提供するために使用されます。
value 属性を設定して、共有するデータを設定します。

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

3. Contextのプロバイダコンポーネント

Contentxt の Provider コンポーネントは、他のコンポーネントによって共有されるデータを提供するために使用されます。
value 属性を設定して、共有するデータを設定します。

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

ヒント: 共有データを使用するコンポーネントを、コンポーネント消費コンポーネントと呼びます。

 クラス.contextType

contextType 属性をコンポーネント クラスに追加して、Context オブジェクトを取得します。

MyClass.contextType = MyContext;

ヒント:クラス
にマウントされたcontextType属性は、React.createContext()によって作成されたContextオブジェクトに再割り当てされますこれにより、this.contextを使用して最新のContextの値を使用できるようになります。レンダリング関数を含め、どのライフサイクルでもアクセスできます

//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 をサブスクライブする


 

 コンテキスト.コンシューマ

<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>
   }

コンテキストの更新
プロバイダーの値が変更されると、その内部にあるすべての消費コンポーネントが再レンダリングされます。
 

//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

断片

 シーン 1:

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

ヒント: React では、コンポーネント インターフェイスはルート タグを 1 つだけ持つことができます。

 シーン 2:

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

フラグメントを使用すると、DOM に余分なノードを追加せずに、子要素をまとめてラップできます。
 

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

最終的なページのレンダリング結果:

1.短い構文をフラグメント化する

<React.Fragment></React.Fragment>の代わりに<> </ >を使用します。

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

ヒント:
フラグメントは最終的に DOM にレンダリングされないため、イベントをバインドしたり、フレームメントに他の属性を設定したりしないでください。現在、キー属性の設定のみがサポートされています。

 エラー境界_概念

 通常、1 つのコンポーネントでエラーが発生すると、アプリケーション全体がクラッシュし、ページが空白になります。

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

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

エラーのないコンポーネントのレンダリングを続行したい場合は、エラー境界を使用できます。
ErrorBounds はReact コンポーネントです。
エラー境界は、サブコンポーネント ツリー内の任意の場所で発生する JavaScript エラーをキャッチして出力し、代替 UI をレンダリングできます。
エラー境界レンダリング中、ライフサイクル メソッド内、およびサブコンポーネント ツリー全体のコンストラクター内でエラーを捕捉します。

 ヒント: エラー境界は、次のシナリオで生成されたエラーをキャプチャできません:
1. イベント処理
2. 非同期コード (setTimeout または requestAnimationFrame コールバック関数など)

3. (そのサブコンポーネントではなく) それ自体によってスローされるエラー

 エラー境界_アプリケーション

1. エラー境界コンポーネント
クラスを定義する2 つのライフサイクル メソッド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 でサポートされているいくつかのメソッドを使用してキャプチャできます。

 トライ/キャッチ

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 は構文エラーと実行時エラーをキャプチャでき、現在のウィンドウで実行される JS スクリプトにエラーがある限り、エラーがキャプチャされます。
 

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

参照と DOM

 Ref は、DOM要素にアクセスする方法を提供します

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

Create Ref は
React.createRef() を使用して作成されます。
通常、Ref はインスタンス プロパティに割り当てられるため、コンポーネント全体で参照できます。
 

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

Refs を使用してref
属性を対応する React 要素に設定することは、 ref を使用して DOM ノードへの参照を保存することと同じです。
 

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

Ref へのアクセスref がrenderの要素に渡される
と、 ref現在のプロパティでそのノードへの参照にアクセスできます。
 

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

ヒント:
React は、コンポーネントがマウントされるときに DOM 要素を現在のプロパティに渡し、コンポーネントがアンマウントされるときに null 値を渡します。

ref は、componentDidMountライフサイクル フックがトリガーされるに更新されます。

おすすめ

転載: blog.csdn.net/m0_58719994/article/details/133162794