[React]ContextAPI의 역모드

ContextAPI와useState는 원래 조합이 안 돼요.


ContextAPI의 기능은 어셈블리 계층 간에 데이터를 전송하는 것입니다.그러나 여기서 주의해야 할 것은useState로 Provider가 설정한 값을 관리하면 Provider를 가진 모든 트리를 다시 나타낼 수 있다는 것이다.이 작법은 최악의 반모드다.

역모드


고급 구성 요소useState의 스케줄러가 업데이트를 사용하여 Provider에 전달된 값을 사용하고 있습니다.모든 업데이트 값이 업데이트되면 모든 구성 요소가 다시 나타납니다.이러한 방법은 ContextAPI 설명에서 자주 볼 수 있습니다.그러나 한 값의 변경으로 모두 다시 쓰면 상태 관리의 필요성이 사라진다.이것은 해서는 안 되는 서법이다.
import { createContext, useContext, useState } from "react";

type ValueType = { [key: string]: number | undefined };

const context = createContext<ValueType>(undefined as never);

const Component = ({ name }: { name: string }) => {
  const value = useContext(context);
  console.log(name);
  return (
    <div>
      {name}:{value[name]}
    </div>
  );
};

const Page = () => {
  const [value, setValue] = useState<ValueType>({});
  console.log("Main");
  return (
    <>
      <button onClick={() => setValue((v) => ({ ...v, A: (v["A"] || 0) + 1 }))}>
        A
      </button>
      <button onClick={() => setValue((v) => ({ ...v, B: (v["B"] || 0) + 1 }))}>
        B
      </button>
      <button onClick={() => setValue((v) => ({ ...v, C: (v["C"] || 0) + 1 }))}>
        C
      </button>
      <context.Provider value={value}>
        <Component name="A" />
        <Component name="B" />
        <Component name="C" />
      </context.Provider>
    </>
  );
};

export default Page;
  • A 키를 누른 상태에서 출력

  • Main
    A
    B
    C
    

    불필요한 리메이크를 일으키지 않는 모드


    useRef에서 만든 객체를 Provider에 전달합니다.Context 업데이트는 무음판에서 이루어지기 때문에 다시 써도 다시 쓰지 않습니다.다시 쓸 구성 요소는 각각state를 다시 써서 다시 쓸 것을 알립니다.Context가 보유한 데이터는 서브어셈블리 내의 소음기입니다.
    이 쓰기 방법에 따라 버튼 A를 누르면 렌더링<Component name="A" />만 하면 됩니다.
    import {
      createContext,
      Dispatch,
      SetStateAction,
      useContext,
      useEffect,
      useRef,
      useState,
    } from "react";
    
    type ValueType = {
      [key: string]: Dispatch<SetStateAction<number | undefined>>;
    };
    
    const context = createContext<ValueType>(undefined as never);
    
    const Component = ({ name }: { name: string }) => {
      console.log(name);
      const [value, setValue] = useState<number>();
      const dispatches = useContext(context);
      useEffect(() => {
        dispatches[name] = setValue;
        return () => {
          delete dispatches[name];
        };
      }, [name]);
      return (
        <div>
          {name}:{value}
        </div>
      );
    };
    
    const Page = () => {
      console.log("Main");
      const dispatches = useRef<ValueType>({}).current;
      return (
        <>
          <button onClick={() => dispatches["A"]?.((v) => (v || 0) + 1)}>A</button>
          <button onClick={() => dispatches["B"]?.((v) => (v || 0) + 1)}>B</button>
          <button onClick={() => dispatches["C"]?.((v) => (v || 0) + 1)}>C</button>
          <context.Provider value={dispatches}>
            <Component name="A" />
            <Component name="B" />
            <Component name="C" />
          </context.Provider>
        </>
      );
    };
    
    export default Page;
    
  • A 키를 누른 상태에서 출력

  • A
    

    Context 측에 데이터를 보유하도록 하면서 불필요한 렌더링 방지 모드


    구조가 좀 복잡하지만 같은 이름의 데이터가 여러 구성 요소에 사용되는 상황에서도 참을 수 있다.Context 측에서 데이터를 저장하는 동시에 렌더링을 촉진하는 모니터도 관리합니다.
    그러면 해당 이름의 데이터만 사용하는 어셈블리가 다시 렌더링됩니다.
    import {
      createContext,
      Dispatch,
      SetStateAction,
      useContext,
      useEffect,
      useRef,
      useState,
    } from "react";
    
    type ValueType = {
      dispatches: { [key: string]: Set<Dispatch<SetStateAction<{}>>> };
      values: { [key: string]: number | undefined };
    };
    
    const context = createContext<ValueType>(undefined as never);
    
    const Component = ({ name }: { name: string }) => {
      console.log(name);
      const [_, setValue] = useState<{}>();
      const { values, dispatches } = useContext(context);
      useEffect(() => {
        if (dispatches[name]) dispatches[name].add(setValue);
        else dispatches[name] = new Set([setValue]);
        return () => {
          dispatches[name].delete(setValue);
        };
      }, [name]);
      return (
        <div>
          {name}:{values[name]}
        </div>
      );
    };
    
    const Page = () => {
      console.log("Main");
      const manager = useRef<ValueType>({ dispatches: {}, values: {} }).current;
      const { dispatches, values } = manager;
      return (
        <>
          <button
            onClick={() => {
              values["A"] = (values["A"] || 0) + 1;
              dispatches["A"].forEach((v) => v({}));
            }}
          >
            A
          </button>
          <button
            onClick={() => {
              values["B"] = (values["B"] || 0) + 1;
              dispatches["B"].forEach((v) => v({}));
            }}
          >
            B
          </button>
          <button
            onClick={() => {
              values["C"] = (values["C"] || 0) + 1;
              dispatches["C"].forEach((v) => v({}));
            }}
          >
            C
          </button>
          <context.Provider value={manager}>
            <Component name="A" />
            <Component name="B" />
            <Component name="C" />
            <Component name="A" />
            <Component name="B" />
            <Component name="C" />
          </context.Provider>
        </>
      );
    };
    
    export default Page;
    
  • A 키를 누른 상태에서 출력
  • A
    A
    

    총결산


    ContextAPI는 Provider 내에서 데이터를 배포하는 데 사용되는 기능입니다.일부는 이상한 오해가 있었지만, 쓸모없는 재렌더링 기능은 절대 아니었다.특정 구성 요소를 재현하도록 재촉할 때, 각 구성 요소 안에서 setState를 하고 스케줄러를 사용합니다.또한 setState의 주요 기능은 재재현 이벤트를 생성하기 위한 것이지 데이터를 저장하는 것이 아니다.데이터를 저장하려면useRef가 올바른 선택입니다.
    이번에 해설은 모니터를 벗겨내는 호출로 작성돼 잘 포장하면 사용하기 쉽다.
    리액트를 사용할 때 가장 중요한 것은 적절한 시기에 전성기를 부르는 것이다.그것만 할 수 있다면 정음판으로 데이터를 처리하는 것도 전혀 문제가 없다.다시 돋보이는 폭포 수행을 응용 프로그램에 편입하지 않도록 시기를 잘 관리해 주십시오.

    좋은 웹페이지 즐겨찾기