리코일의 아톰을 초기화할 때 effect를 한 번만 부르고 싶은 경우.

과제.


맞춤형 갈고리에서tom을 사용할 때 전체 응용 프로그램에서 이 맞춤형 갈고리를 여러 번 호출하더라도 같은state를 참고할 수 있습니다.
이state와 연결을 맺어 초기화 처리를 하려는 effect의 경우 (예를 들어 키다운에서 state를 업데이트하는 등),recoil 자체는 이 기능을 가지고 있지만 (tom에 effects_UNSTABLE set/get의 정시 호출 처리를 원하는 경우에만 사용할 수 없습니다.)
사용자 정의 연결에서 일반적으로useEffect를 사용한다면,useEffect는 구성 요소 단위로 실행되기 때문에, 프로그램의 여러 곳에서 사용자 정의 연결을 호출할 때 같은 effect가 여러 번 호출됩니다.
생명주기로서 응용의 초기화 정시 처리이기 때문에 루트 구성 요소의 effect에서 Tom의 초기화와 관련된 처리를 호출할 수 있지만 Tom의 선언과 실제 실행 초기화의 장소가 각각 정의되어 전망이 좋지 않다.

해결책

dangerouslyAllowMutability 옵션으로 effect를 실행했는지 여부를 만듭니다.useEffect로 초기화하면ref처럼 이 state를 파괴적으로 변경합니다.
useMyHook.ts
const isInitializedState = atom({
  key: "isInitializedState",
  default: { value: false },
  dangerouslyAllowMutability: true
});

const useMyHook = () => {
  // atom を使う処理
  const isInitializedRef = useRecoilValue(isInitializedState);
  useEffect(() => {
    if (isInitializedRef.value) return;
    isInitializedRef.value = true;
    // ...初期化処理
  }, []);
};
다음은 상기 코드까지의 방안과 문제점을 열거한다.

시나리오 1 및 문제점


사용자 정의 연결에서useEffect를 사용하여 초기화 처리를 실행합니다.
useMyHook.ts
const useMyHook = () => {
  // atom を使う処理
  useEffect(() => {
    // ...初期化処理
  }, []);
 };
만약 이 사용자 정의 연결이 프로그램 내 구성 요소에서 한 번만 사용된다면, 이 쓰기 방법은 문제가 없을 수도 있습니다.
만약 여러 개의 구성 요소가 이 맞춤형 연결을 사용한다면, 모든 구성 요소는useEffect 처리를 할 것입니다. 따라서 이것은 tom을 초기화할 때 단 한 번의 요구를 위반합니다.

시나리오 2 및 문제점


프로젝트 1을 제외하고useRef를 사용하여 초기화 처리된 로고를 미리 가지고 있습니다.
useMyHook.ts
const useMyHook = () => {
  // atom を使う処理
  const isInitialized = useRef(false);
  useEffect(() => {
    if (isInitialized.current) return;
    isInitialized.current = true;
    // ...初期化処理
  }, []);
 };
초기화 처리를 하는 로고가 있다는 구상은 좋지만useRef도 방안 1과 같은 문제점이 있다. 사용자 정의 갈고리를 사용한 모든 구성 요소가 독립적으로 관리되기 때문이다.

시나리오 3 및 문제점


프로젝트 2의useRef가 안 되면 프로그램 전체가 공유하는tom을 로고로 사용합니다.
useMyHook.ts
const isInitializedState = atom({
  key: "isInitializedState",
  default: false,
});

const useMyHook = () => {
  // atom を使う処理
  const [isInitialized, setIsInitialized] = useRecoilState(isInitializedState);
  useEffect(() => {
    if (isInitialized) return;
    setIsInitialized(true);
    // ...初期化処理
  }, []);
 };
해결 방법에 상당히 가까운 코드.
그러나 이 사용자 정의 연결의 문제점은 여러 구성 요소에서 동시에 호출됩니다.
구성 요소 1과 구성 요소 2가 동시에 맞춤형 갈고리를 호출하면, 이 구성 요소에서 맞춤형 갈고리를 호출하는 것을 동기화라고 부른다.
첫 번째 구성 요소setIsInitialized(true)에서 실행되더라도 이 변화를 반영하는 것은 다음tick이기 때문에 두 번째 구성 요소에서 참고한 isInitialized 유지false, 초기화 처리는 두 번 실행됩니다.

최종 코드


useMyHook.ts
const isInitializedState = atom({
  key: "isInitializedState",
  default: { value: false },
  dangerouslyAllowMutability: true
});

const useMyHook = () => {
  // atom を使う処理
  const isInitializedRef = useRecoilValue(isInitializedState);
  useEffect(() => {
    if (isInitializedRef.value) return;
    isInitializedRef.value = true;
    // ...初期化処理
  }, []);
};
방안 3의 문제점은 Tom의 참조와 업데이트가 tick의 말과 같이 낡은 정보를 참조했다는 것이다.
이 문제를 해결하기 위해서는 dangerouslyAllowMutability 옵션을 사용하여 값을 동기화할 수 있습니다.
이렇게 하면 React의useRef처럼 구성 요소의 생명주기와 분리하여 업데이트할 수 있습니다.
useRef를 사용한 상태에서 다시 쓰기 ref.current 를 위해 tom 관리가 필요한 값은 원본 값을 대상에 직접 포장하는 것이 아니라 대상의 필드 값을 다시 대입하는 형식으로 업데이트됩니다.dangerously 이름 사용 기능은 신중해야 하며, 이번 경우 사용자 정의 연결에 폐쇄된tom으로 관리할 수 있다.

좋은 웹페이지 즐겨찾기