反応インタビューのコンテキストの値が変更された場合、すべての内部サブコンポーネントが変更されるかどうか

テストコード

// context
const state = {
    
    
    a: 1,
    b: 1,
}
const context = createContext(state);

export default context;
// A组件
const A = () => {
    
    
    const {
    
     a } = useContext(context);
    return (<div>{
    
    a}</div>)
}
export default A;

// B组件
const B = () => {
    
    
    const {
    
     b } = useContext(context);
    return (<div>{
    
    b}</div>)
}
export default B;

// C组件, 不引用context
const C = () => {
    
    
    return (<div>cccc</div>)
}
export default C;

// APP.js
function App() {
    
    
	const [a, setA] = useState(-1);
	return (
		<div>
			<Context.Provider value={
    
    {
    
    
				a,
				b
			}}>
	          <A />
	          <B />
	          <C />
	      	</Context.Provider>
	      	<button onClick={
    
    () => setA(a+1)}>+++</button>
      	</div>
     );

ボタンをクリックすると、ABC の 3 つのコンポーネントのうちどれが更新されるでしょうか?


答えは、App コンポーネントの状態が変化し、すべてのコンポーネントが更新されるため、3 つすべてが更新されるということです。したがって、コンテキストが B および C コンポーネントに影響を与えるかどうかを知ることは不可能です。

親コンポーネントの状態更新を解決して子コンポーネントを更新するには、ABC の 3 つのコンポーネントのエクスポートのデフォルトにメモ メソッドを追加する必要があります。2 番目のパラメータは PropsAreEqual なので、true が返されます。直接。

変換後は次のようになります。

// A组件
// ...
export default memo(A, () => true);

// B组件
// ...
export default memo(B, () => true);

// C组件, 不引用context
// ...
export default memo(C, () => true);

この時点で、ボタンをもう一度クリックすると、更新がトリガーされます。


答えは、AB は更新をトリガーしますが、C は更新をトリガーしないということです。

しかし、a の値を更新しただけなのに、なぜ a を使用しない B コンポーネントが更新されるのでしょうか?

これは、コンテキストを共有しており、その値がオブジェクトであり、毎回新しいオブジェクトが再生成されるため、B コンポーネントはコンテキストが更新されたと認識し、レンダリングをトリガーします。

したがって、context の値が変更される限り、useContext(context) の使用はすべて更新されることがわかります。

C コンポーネントに D コンポーネントを追加し、D コンポーネントがコンテキストを参照できるようにするとどうなるでしょうか。

// C组件, 不引用context
const C = () => {
    
    
    return (<div>
	    cccc
	    <D/>
    </div>)
}
export default memo(C, () => true);
// D组件
const D = () => {
    
    
    const {
    
     b } = useContext(context);
    return (<div>{
    
    b}</div>)
}
export default memo(D, () => true);

ボタンをクリックすると C は更新をトリガーしますか?

答えは「いいえ」です。ABD は更新されましたが、C は更新されていません。彼の推測をさらに検証した。

変更により BD を変更したくない場合はどうすればよいですか?

次に、状態から b を逆アセンブルし、bContext を再作成します。

// App组件改为:
function App() {
    
    
const [a, setA] = useState(-1);
const [b, setB] = useState(-1);
	return (
		<div>
			<Context.Provider value={
    
    {
    
    a}}>
			  <BContext.Provider value={
    
    {
    
    b}}>
			    <A />
			    <B />
			    <C />
			  </BContext.Provider>
			</Context.Provider>
			<button onClick={
    
    () => setA(a+1)}>++a</button>
			<button onClick={
    
    () => setA(b+1)}>++b</button>
		</div>
	)
}
// B组件和D组件都更新为引用bContext
import bContext from "./context/b"
// ...
const {
    
     b } = useContext(bContext);
// ...

この時点でaボタンをクリックするとBDが更新されると思いますか?

答えは「更新される」です。なぜですか?

BContext の値は毎回新しいオブジェクトであるため、常に変化していると彼は考えています。そのため、オブジェクトを渡したい場合は、外側の層で useMemo を使用してオブジェクトを再定義するのが最善の方法です。{a}も同じです。

// App改为
 const aVal = useMemo(() => ({
    
     a }), [a])
 const bVal = useMemo(() => ({
    
     b }), [b])
 
<Context.Provider value={
    
    aVal}>
	<BContext.Provider value={
    
    bVal}>
	   <A />
	   <B />
	   <C />
	 </BContext.Provider>
</Context.Provider>

この時点で a の値を更新しても BD コンポーネントには影響せず、A コンポーネントのみが更新されます。同時に、b の値を更新しても A コンポーネントの更新はトリガーされず、BD の更新のみがトリガーされます。C は、a と b の 2 つの値の更新の影響を受けません。

これまでのところ、コンテキストの値が更新された場合、そのコンテキストを使用しているコンポーネントにのみ影響し、他のコンポーネントには影響を与えないと結論付けることができます (制御がメモ内で行われる場合)。

おすすめ

転載: blog.csdn.net/qq_28992047/article/details/132073796