programing

반응 후크의 oldValues와 newValues를 비교하는 방법 useEffect?

closeapi 2023. 3. 12. 10:50
반응형

반응 후크의 oldValues와 newValues를 비교하는 방법 useEffect?

rate, sendAmount 및 receiveAmount의 3가지 입력이 있다고 칩시다.나는 그 3개의 입력을 useEffect 확산 파라미터에 넣었다.규칙은 다음과 같습니다.

  • 변경된 sendAmount가 됩니다.receiveAmount = sendAmount * rate
  • receiveAmount를 합니다.sendAmount = receiveAmount / rate
  • 비율이 바뀌면 는 계산한다.receiveAmount = sendAmount * ratesendAmount > 0 내가 계산한다.sendAmount = receiveAmount / ratereceiveAmount > 0

다음은 문제를 나타내는 코드 및 박스 https://codesandbox.io/s/pkl6vn7x6j 입니다.

요?oldValues ★★★★★★★★★★★★★★★★★」newValues 좋아하다componentDidUpdate3시?

감사해요.


.usePrevious https://codesandbox.io/s/30n01w2r06https.io/s/30n01w2r06

저는 으로 사용할 수 .useEffect각 변경이 같은 네트워크콜로 이어지기 때문입니다.그래서 저도 쓰고 있어요.changeCount변경내용을 추적할 수 있습니다. ★★★★★★★★★★★★★★★★★.changeCount로컬로부터의 변경만 추적하기 때문에 서버로부터의 변경으로 인한 불필요한 네트워크콜을 방지할 수 있습니다.

useRef를 사용하여 사용자 지정 후크를 작성하여 이전 소품을 제공할 수 있습니다.

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

에 하세요.useEffect

const Component = (props) => {
    const {receiveAmount, sendAmount } = props
    const prevAmount = usePrevious({receiveAmount, sendAmount});
    useEffect(() => {
        if(prevAmount.receiveAmount !== receiveAmount) {

         // process here
        }
        if(prevAmount.sendAmount !== sendAmount) {

         // process here
        }
    }, [receiveAmount, sendAmount])
}

두 개의 ,, 개, 개, 2, 개, 개, 개, 2, ,, , 개, to, two, to, to, to, to, to, to, however, to, however, to, to, to, to, to, to, to, to, however, however, however, however, however,useEffect 변경 한다.

을 있는 usePrevious:

①의 .tsx★★★★

import { useEffect, useRef } from "react";

const usePrevious = <T extends unknown>(value: T): T | undefined => {
  const ref = useRef<T>();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};

또 에,.ts★★★★

import { useEffect, useRef } from "react";

const usePrevious = <T>(value: T): T | undefined => {
  const ref = useRef<T>();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
};

옵션 1 - 값이 변경되면 useEffect 실행

const Component = (props) => {

  useEffect(() => {
    console.log("val1 has changed");
  }, [val1]);

  return <div>...</div>;
};

데모

옵션 2 - useHasChanged 훅

현재 값을 이전 값과 비교하는 것은 일반적인 패턴이며 구현 세부 정보를 숨기는 자체 사용자 지정 후크를 정당화합니다.

const Component = (props) => {
  const hasVal1Changed = useHasChanged(val1)

  useEffect(() => {
    if (hasVal1Changed ) {
      console.log("val1 has changed");
    }
  });

  return <div>...</div>;
};

const useHasChanged= (val: any) => {
    const prevVal = usePrevious(val)
    return prevVal !== val
}

const usePrevious = (value) => {
    const ref = useRef();
    useEffect(() => {
      ref.current = value;
    });
    return ref.current;
}


데모

커스텀 훅이 필요 없는 대체 솔루션인 인정된 답변에서 벗어나는 방법:

const Component = ({ receiveAmount, sendAmount }) => {
  const prevAmount = useRef({ receiveAmount, sendAmount }).current;

  useEffect(() => {
    if (prevAmount.receiveAmount !== receiveAmount) {
     // process here
    }

    if (prevAmount.sendAmount !== sendAmount) {
     // process here
    }

    return () => { 
      prevAmount.receiveAmount = receiveAmount;
      prevAmount.sendAmount = sendAmount;
    };
  }, [receiveAmount, sendAmount]);
};

이는 "여기에 프로세스" 비트에 있는 모든 값에 대해 실제로 이전 값을 참조해야 한다고 가정합니다. 조건 이 스트레이트(를 한!==여기서 가장 심플한 솔루션은 다음과 같습니다.

const Component = ({ receiveAmount, sendAmount }) => {
  useEffect(() => {
     // process here
  }, [receiveAmount]);

  useEffect(() => {
     // process here
  }, [sendAmount]);
};

방금 리액트-델타를 발표했는데 이런 종류의 시나리오를 해결했어요제 생각에는useEffect★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

책임

  1. 내의 합니다.Object.is
  2. #1의 결과에 따라 효과/청소 콜백을 실행합니다.

책임의 분할

react-deltauseEffect훅을 끼우다

책임 #1

책임 #2

, 이은 더합니다.useEffect/useRef★★★★★★★★★★★★★★★★★★.

원하신다면useEffect「 」 「 」:

const usePreviousEffect = (fn, inputs = []) => {
  const previousInputsRef = useRef([...inputs])

  useEffect(() => {
    fn(previousInputsRef.current)
    previousInputsRef.current = [...inputs]
  }, inputs)
}

그리고 이렇게 사용하세요.

usePreviousEffect(
  ([prevReceiveAmount, prevSendAmount]) => {
    if (prevReceiveAmount !== receiveAmount) // side effect here
    if (prevSendAmount !== sendAmount) // side effect here
  },
  [receiveAmount, sendAmount]
)

처음 효과를 실행할 때 이전 값이 사용자에게 전달되는 것에 주의해 주세요.fn초기 입력값과 동일합니다.이것은 값이 변경되지 않은 상태에서 작업을 수행하려는 경우에만 문제가 됩니다.

되어 있지 않기 할 수 .useEffect, 를 들어 ""를 사용하여 저장하십시오.useRef 상태가 사용 에 상태 되었을 수 setState이치노

은 이, this, 적, 의 좋은 활용 사례입니다.useReducerRedux와 같은 저장소를 제공하고 각각의 패턴을 구현할 수 있습니다.상태 업데이트는 명시적으로 수행되므로 어떤 상태 속성이 업데이트되는지 확인할 필요가 없습니다. 이는 이미 디스패치된 액션에서 명확합니다.

다음은 를 제시하겠습니다.

function reducer({ sendAmount, receiveAmount, rate }, action) {
  switch (action.type) {
    case "sendAmount":
      sendAmount = action.payload;
      return {
        sendAmount,
        receiveAmount: sendAmount * rate,
        rate
      };
    case "receiveAmount":
      receiveAmount = action.payload;
      return {
        sendAmount: receiveAmount / rate,
        receiveAmount,
        rate
      };
    case "rate":
      rate = action.payload;
      return {
        sendAmount: receiveAmount ? receiveAmount / rate : sendAmount,
        receiveAmount: sendAmount ? sendAmount * rate : receiveAmount,
        rate
      };
    default:
      throw new Error();
  }
}

function handleChange(e) {
  const { name, value } = e.target;
  dispatch({
    type: name,
    payload: value
  });
}

...
const [state, dispatch] = useReducer(reducer, {
  rate: 2,
  sendAmount: 0,
  receiveAmount: 0
});
...

대부분의 투표된 답변에 주의하세요.에서는, 「」의 바리에이션에 대해 설명합니다.usePrevious에서는, 너무 많은 리다이렉트(1) 또는 원래의(2)와 같은 값을 얻을 수 있습니다.

다음과 같은 것이 필요합니다.

  1. [value] 관계로서useEffectvalue 사항
  2. 「」의 할당JSON.parse(JSON.stringify(value))딥 카피) ('Deep Copy')ref.current 말하다useEffect 하기

업그레이드된 후크:

const usePrevious = <T>(value: T): T => {
  const ref: any = useRef<T>()

  useEffect(() => {
    ref.current = JSON.parse(JSON.stringify(value))
  }, [value])

  return ref.current
}

여기 제가 사용하는 커스텀 훅이 있습니다.사용하는 것보다 직관적이라고 생각합니다.

import { useRef, useEffect } from 'react'

// useTransition :: Array a => (a -> Void, a) -> Void
//                              |_______|  |
//                                  |      |
//                              callback  deps
//
// The useTransition hook is similar to the useEffect hook. It requires
// a callback function and an array of dependencies. Unlike the useEffect
// hook, the callback function is only called when the dependencies change.
// Hence, it's not called when the component mounts because there is no change
// in the dependencies. The callback function is supplied the previous array of
// dependencies which it can use to perform transition-based effects.
const useTransition = (callback, deps) => {
  const func = useRef(null)

  useEffect(() => {
    func.current = callback
  }, [callback])

  const args = useRef(null)

  useEffect(() => {
    if (args.current !== null) func.current(...args.current)
    args.current = deps
  }, deps)
}

사용할 수 있습니다.useTransition다음과 같이 합니다.

useTransition((prevRate, prevSendAmount, prevReceiveAmount) => {
  if (sendAmount !== prevSendAmount || rate !== prevRate && sendAmount > 0) {
    const newReceiveAmount = sendAmount * rate
    // do something
  } else {
    const newSendAmount = receiveAmount / rate
    // do something
  }
}, [rate, sendAmount, receiveAmount])

도움이 됐으면 좋겠다.

매우 간단한 소품 비교를 위해useEffect쉽게 확인할 수 있습니다.

const myComponent = ({ prop }) => {
  useEffect(() => {
    ---Do stuffhere----
  }, [prop])
}

useEffect그러면 프로펠이 변경된 경우에만 코드가 실행됩니다.

Ref를 사용하면 새로운 버그가 앱에 도입됩니다.

그럼 이 .usePrevious「 」 「 」 、 「 」 。

  1. prop.min Time: 5 == > ref.current = 5 | ref.current 설정
  2. prop.min Time: 5 == > ref.current = 5 | 새 값은 ref.current와 동일합니다.
  3. prop.min Time: 8 ==> ref.current = 5 | 새 값이 ref.current와 같지 않습니다.
  4. prop.min Time: 5 == > ref.current = 5 | 새 값은 ref.current와 동일합니다.

알 수 있듯이 있지 않습니다.ref는 '우리'를 사용하고 때문입니다.useEffect

useState가 아닌 useImer를 사용하여 상태에 액세스할 수 있습니다.예: https://css-tricks.com/build-a-chat-app-using-react-hooks-in-100-lines-of-code/

나는 위의 어떤 대답도 마음에 들지 않았고, 나는 일련의 부란을 통과할 수 있는 능력을 원했고, 만약 그 중 하나가 사실이라면, 그래서 다시 연마할 수 있다.

/**
 * effect fires if one of the conditions in the dependency array is true
 */
export const useEffectCompare = (callback: () => void, conditions: boolean[], effect = useEffect) => {
  const shouldUpdate = useRef(false);
  if (conditions.some((cond) => cond)) shouldUpdate.current = !shouldUpdate.current;
  effect(callback, [shouldUpdate.current]);
};

//usage - will fire because one of the dependencies is true.
useEffectCompare(() => {
  console.log('test!');
}, [false, true]);

여기 타이프스크립트 버전 Aadit M Shah's Answer가 있습니다.

을 에에이 i i i i i i i i i i 。useTransition로로 합니다.usePrevioususeTransition반응하다

import { useEffect, useRef, useState } from 'react';

const usePrevious = <T extends any[],>(callback: (prev: T) => void, deps: T): void => {
  const callbackRef = useRef<null | ((prev: T) => void)>(null);

  useEffect(() => {
    callbackRef.current = callback;
  }, [callback]);

  const depsRef = useRef<null | T>(null);

  const [initial, setInitial] = useState(true);

  useEffect(() => {
    if (!initial && depsRef.current !== null && callbackRef.current !== null) {
      callbackRef.current(depsRef.current);
    }

    depsRef.current = deps;
    setInitial(false);
  }, deps);
}

export default usePrevious;

사용방법:

  usePrevious<[boolean]>(([prevIsOpen]) => {
    console.log('prev', prevIsOpen);
    console.log('now', isOpen);
  }, [isOpen])

사용자의 경우(단순 객체):

useEffect(()=>{
  // your logic
}, [rate, sendAmount, receiveAmount])

그 외의 경우(복잡한 객체)

const {cityInfo} = props;
useEffect(()=>{
  // some logic
}, [cityInfo.cityId])

언급URL : https://stackoverflow.com/questions/53446020/how-to-compare-oldvalues-and-newvalues-on-react-hooks-useeffect

반응형