私は新しいReact Context APIを理解しようとしてそれで遊んでいました。プロバイダーへのデータが更新されたときにすべてが再レンダリングされる単純なケースを確認したかっただけです。
したがって、私の例では、App
コンポーネントがあります-これは次のような状態です-
this.state = {
number - A random number
text - A static text
}
状態からnumber
とtext
を含む新しいReactコンテキストをここから作成し、値を2つのコンシューマーNumber
とText
。
したがって、私の仮定は、乱数が更新されると、コンテキストが変更され、両方のコンポーネントが再レンダリングをトリガーすることです。
しかし、実際には値は更新されていますが、再レンダリングは行われていません。
だから、私の質問-
通常の再レンダリングを介して伝播されないコンテキストに更新されますか?コンテキストが変わると、ログや色が変化しないので、.
そのプロバイダーのすべてのコンシューマーは更新されていますか?
通常の再レンダリングを介して伝播されないコンテキストに更新されますか?コンテキストが変わると、ログや色が変化しないので、.
コンテキスト値の更新は、プロバイダーのすべての子に対して再レンダリングをトリガーするのではなく、コンシューマー内からレンダリングされるコンポーネントのみをトリガーするため、数値コンポーネントにはコンシューマーが含まれていますが、数値コンポーネントは再レンダリングされませんではなく、コンシューマ内のレンダリング関数だけなので、コンテキストの更新時に値が変化します。この方法は、すべての子に対して再レンダリングをトリガーしないため、非常に高いパフォーマンスを発揮します。
そのプロバイダーのすべてのコンシューマーは更新されていますか?
そのプロバイダーのすべてのコンシューマーは更新サイクルを通過しますが、再レンダリングするかどうかは、仮想仮想DOMの比較によって決定されます。このデモは、コンソールで確認できますsandbox
[〜#〜]編集[〜#〜]
確認する必要があるのは、コンポーネントがContextProviderコンポーネントの子としてレンダリングされ、インラインでレンダリングしてContextProviderの状態を更新するのではなく、ハンドラーをハンドラーに渡して、その中にあるすべてのコンポーネントの再レンダリングがトリガーされるためです。 ContextProvider
パフォーマンスの使い方
App.js
render() {
return (
<AppContext.Provider
value={{ ...this.state, updateNumber: this.updateNumber }}
>
{this.props.children}
</AppContext.Provider>
);
}
index.js
class Data extends React.Component {
render() {
return (
<div>
<h1>Welcome to React</h1>
<Number />
<Text />
<TestComp />
<AppContext.Consumer>
{({ updateNumber }) => (
<button onClick={updateNumber}>Change Number </button>
)}
</AppContext.Consumer>
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(
<App>
<Data />
</App>,
rootElement
);
パフォーマンスの低い使用法
App.js
class App extends Component {
constructor() {
super();
this.state = {
number: Math.random() * 100,
text: "testing context api"
};
}
updateNumber = () => {
const randomNumber = Math.random() * 100;
this.setState({ number: randomNumber });
};
render() {
return (
<AppContext.Provider value={this.state}>
<div>
<h1>Welcome to React</h1>
<Number />
<Text />
<TestComp />
<button onClick={this.updateNumber}>Change Number </button>
</div>
</AppContext.Provider>
);
}
}
useContext
フックに基づく質問の更新は次のとおりです。
const value = useContext(MyContext)
コンポーネントの上の最も近い_
<MyContext.Provider>
_が更新されると、このフックは、そのvalue
プロバイダーに渡された最新のコンテキストMyContext
で再レンダリングをトリガーします。祖先が_React.memo
_またはshouldComponentUpdate
を使用している場合でも、rerenderはコンポーネント自体でから始まりますuseContext
を使用します。componentが
useContext
を呼び出すと、常に再レンダリングされますコンテキスト値の変更。コンポーネントの再レンダリングにコストがかかる場合は、メモ化を使用してコンポーネントを最適化できます。
したがって、以下のコード例に示すように、コンポーネントNumber
およびText
は、両方に直接useContext(AppContext)
が含まれているため、コンテキスト値が変更されるたびに再レンダリングされます。
_const AppContext = React.createContext();
const Number = React.memo(props => {
const renderCount = useRenderCount();
const contextNo = React.useContext(AppContext);
return (
<div style={{ backgroundColor: `${randomColor()}` }}>
Number: rendered {renderCount.current} times.
</div>
);
});
const Text = React.memo(() => {
const renderCount = useRenderCount();
const context = React.useContext(AppContext);
return (
<div style={{ backgroundColor: `${randomColor()}` }}>
Text: rendered {renderCount.current} times. I rerender with context value
changes!
</div>
);
});
const App = () => {
const [ctxVal, setCtxVal] = React.useState(0);
const [prop, setProp] = React.useState(0);
return (
<AppContext.Provider value={ctxVal}>
<Number prop={prop} />
<Text />
<button onClick={() => setCtxVal(ctxVal + 1)}>
Change context value
</button>
<button onClick={() => setProp(prop + 1)}>
Only change prop in Number
</button>
</AppContext.Provider>
);
};
function useRenderCount() {
const renderCount = React.useRef(1);
React.useEffect(() => {
renderCount.current += 1;
});
return renderCount;
}
function randomColor() {
const letters = "0123456789ABCDEF"; let color = "#";
for (let i = 0; i < 6; i++) color += letters[Math.floor(Math.random() * 16)];
return color;
}
ReactDOM.render(<App />, document.getElementById("root"));
_
_<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js" integrity="sha256-32Gmw5rBDXyMjg/73FgpukoTZdMrxuYW7tj8adbN8z4=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js" integrity="sha256-bjQ42ac3EN0GqK40pC9gGi/YixvKyZ24qMP/9HiGW7w=" crossorigin="anonymous"></script>
<div id="root"></div>
_