目次
コンテキストの役割
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ライフサイクル フックがトリガーされる前に更新されます。