useEffect 훅을 발생시킨 의존관계 배열 변수 확인
어떤 변수인지 쉽게 판별할 수 있는 방법이 있을까요?useEffect
의 의존관계 배열이 함수 재기동을 트리거합니까?
각 변수를 로그아웃하는 것만으로 오해의 소지가 있습니다.a
함수와b
는, 로그에 기록했을 때에 같은 것으로 표시되는 오브젝트입니다만, 실제로는 다른 오브젝트로, useEffect의 발화를 일으킵니다.
예를 들어 다음과 같습니다.
React.useEffect(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d])
현재의 메서드에서는 과도한 useEffect 콜의 원인이 되는 동작을 인식할 때까지 의존관계 변수를 하나씩 삭제하고 있습니다만, 이 범위를 좁힐 수 있는 더 좋은 방법이 있을 것입니다.
저는 여러 가지 대답에서 조금씩 떼어내서 제 갈고리를 만들었습니다.그냥 떨어뜨릴 수 있는 능력을 원했어요useEffect
트리거된 의존관계를 빠르게 디버깅할 수 있습니다.useEffect
.
const usePrevious = (value, initialValue) => {
const ref = useRef(initialValue);
useEffect(() => {
ref.current = value;
});
return ref.current;
};
const useEffectDebugger = (effectHook, dependencies, dependencyNames = []) => {
const previousDeps = usePrevious(dependencies, []);
const changedDeps = dependencies.reduce((accum, dependency, index) => {
if (dependency !== previousDeps[index]) {
const keyName = dependencyNames[index] || index;
return {
...accum,
[keyName]: {
before: previousDeps[index],
after: dependency
}
};
}
return accum;
}, {});
if (Object.keys(changedDeps).length) {
console.log('[use-effect-debugger] ', changedDeps);
}
useEffect(effectHook, dependencies);
};
다음은 두 가지 예입니다.각각의 예에 대해서, 저는 다음과 같이 생각합니다.dep2
'foo'에서 'bar'로 바뀝니다.예 1은 통과하지 않은 출력을 나타내고 있습니다.dependencyNames
및 예 2는 의 예를 나타내고 있습니다. dependencyNames
.
예 1
이전:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
그 후:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2])
콘솔 출력:
{
1: {
before: 'foo',
after: 'bar'
}
}
개체 키 '1'은 변경된 종속성의 인덱스를 나타냅니다.여기서,dep2
종속성의 두 번째 항목(인덱스 1)이기 때문에 변경됩니다.
예 2
이전:
useEffect(() => {
// useEffect code here...
}, [dep1, dep2])
그 후:
useEffectDebugger(() => {
// useEffect code here...
}, [dep1, dep2], ['dep1', 'dep2'])
콘솔 출력:
{
dep2: {
before: 'foo',
after: 'bar'
}
}
@simbathesailor/use-what-changed
마법처럼 잘 작동한다!
인스톨
npm
/yarn
그리고.--dev
또는--no-save
가져오기 추가:
import { useWhatChanged } from '@simbathesailor/use-what-changed';
전화:
// (guarantee useEffect deps are in sync with useWhatChanged) let deps = [a, b, c, d] useWhatChanged(deps, 'a, b, c, d'); useEffect(() => { // your effect }, deps);
콘솔에 다음과 같은 양호한 차트를 만듭니다.
두 가지 일반적인 원인이 있습니다.
- 다음과 같이 전달되는 일부 개체:
// Being used like:
export function App() {
return <MyComponent fetchOptions={{
urlThing: '/foo',
headerThing: 'FOO-BAR'
})
}
export const MyComponent = ({fetchOptions}) => {
const [someData, setSomeData] = useState()
useEffect(() => {
window.fetch(fetchOptions).then((data) => {
setSomeData(data)
})
}, [fetchOptions])
return <div>hello {someData.firstName}</div>
}
오브젝트 케이스의 수정은 가능한 경우 컴포넌트 렌더 외부에 있는 스태틱오브젝트를 분할합니다.
const fetchSomeDataOptions = {
urlThing: '/foo',
headerThing: 'FOO-BAR'
}
export function App() {
return <MyComponent fetchOptions={fetchSomeDataOptions} />
}
useMemo로 랩할 수도 있습니다.
export function App() {
return <MyComponent fetchOptions={
useMemo(
() => {
return {
urlThing: '/foo',
headerThing: 'FOO-BAR',
variableThing: hash(someTimestamp)
}
},
[hash, someTimestamp]
)
} />
}
기능에도 동일한 개념이 적용되지만 오래된 폐쇄가 발생할 수 있습니다.
갱신하다
실제로 사용해 본 결과, Retsam 솔루션의 몇 가지 측면을 차용한 다음 솔루션이 마음에 듭니다.
const compareInputs = (inputKeys, oldInputs, newInputs) => {
inputKeys.forEach(key => {
const oldInput = oldInputs[key];
const newInput = newInputs[key];
if (oldInput !== newInput) {
console.log("change detected", key, "old:", oldInput, "new:", newInput);
}
});
};
const useDependenciesDebugger = inputs => {
const oldInputsRef = useRef(inputs);
const inputValuesArray = Object.values(inputs);
const inputKeysArray = Object.keys(inputs);
useMemo(() => {
const oldInputs = oldInputsRef.current;
compareInputs(inputKeysArray, oldInputs, inputs);
oldInputsRef.current = inputs;
}, inputValuesArray); // eslint-disable-line react-hooks/exhaustive-deps
};
그런 다음 의존관계 배열 리터럴을 복사하고 오브젝트 리터럴로 변경하기만 하면 됩니다.
useDependenciesDebugger({ state1, state2 });
이를 통해 로깅은 별도의 매개 변수 없이 변수 이름을 인식할 수 있습니다.
제가 아는 바로는 이 작업을 쉽게 수행할 수 있는 방법은 없지만, 종속성과 변경된 로그를 추적하는 커스텀 훅에 드롭할 수 있습니다.
// Same arguments as useEffect, but with an optional string for logging purposes
const useEffectDebugger = (func, inputs, prefix = "useEffect") => {
// Using a ref to hold the inputs from the previous run (or same run for initial run
const oldInputsRef = useRef(inputs);
useEffect(() => {
// Get the old inputs
const oldInputs = oldInputsRef.current;
// Compare the old inputs to the current inputs
compareInputs(oldInputs, inputs, prefix)
// Save the current inputs
oldInputsRef.current = inputs;
// Execute wrapped effect
func()
}, inputs);
};
compareInputs
을 사용하다
const compareInputs = (oldInputs, newInputs, prefix) => {
// Edge-case: different array lengths
if(oldInputs.length !== newInputs.length) {
// Not helpful to compare item by item, so just output the whole array
console.log(`${prefix} - Inputs have a different length`, oldInputs, newInputs)
console.log("Old inputs:", oldInputs)
console.log("New inputs:", newInputs)
return;
}
// Compare individual items
oldInputs.forEach((oldInput, index) => {
const newInput = newInputs[index];
if(oldInput !== newInput) {
console.log(`${prefix} - The input changed in position ${index}`);
console.log("Old value:", oldInput)
console.log("New value:", newInput)
}
})
}
다음과 같이 사용할 수 있습니다.
useEffectDebugger(() => {
// which variable triggered this re-fire?
console.log('---useEffect---')
}, [a, b, c, d], 'Effect Name')
그러면 다음과 같은 출력이 나옵니다.
Effect Name - The input changed in position 2
Old value: "Previous value"
New value: "New value"
useRef를 사용하여 이전 값을 볼 수 있음을 나타내는 다른 스택오버플로 스레드가 있습니다.
https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
React 베타 문서에서는 다음 단계를 권장합니다.
- console.log를 사용하여 종속 어레이를 기록합니다.
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
console.log([todos, tab]);
- 콘솔에서 다른 리렌더 어레이를 마우스 오른쪽 버튼으로 클릭하고 두 어레이 모두에 대해 "글로벌 변수로 저장"을 선택합니다.만약 당신이 엄격한 모드라면 두 개의 연속적인 것을 비교하지 않는 것이 중요할 수 있습니다.
- 각 종속성을 비교합니다.
Object.is(temp1[0], temp2[0]); // Is the first dependency the same between the arrays?
이 질문에는 몇 가지 좋은 답변이 있었습니다만, DX가 마음에 들지 않았습니다.
그래서 저는 가장 사용하기 쉬운 방식으로 변경된 종속성을 기록하는 라이브러리를 작성했고, 두 객체 간의 상세한 비교를 기록하는 기능을 추가했습니다.그러면 객체 내에서 정확히 무엇이 변경되었는지 알 수 있습니다.
나는 그것을 '리액션-무엇이 변화했는가'라고 불렀다.
Readme에는 필요한 예가 모두 포함되어 있습니다.
용도는 매우 간단합니다.
npm install react-what-changed --save-dev
import { reactWhatChanged as RWC } from 'react-what-changed';
function MyComponent(props) {
useEffect(() => {
someLogic();
}, RWC([somePrimitive, someArray, someObject]));
}
이 패키지에는 오브젝트간의 상세한 비교(디프만)를 인쇄하기 위한 2개의 편리한 기능도 있습니다.예를 들어 다음과 같습니다.
import { reactWhatDiff as RWD } from 'react-what-changed';
function MyComponent(props) {
useEffect(() => {
someLogic();
}, [somePrimitive, someArray, someObject]);
RWD(someArray);
}
언급URL : https://stackoverflow.com/questions/55187563/determine-which-dependency-array-variable-caused-useeffect-hook-to-fire
'programing' 카테고리의 다른 글
Angular4 - 폼 제어를 위한 값 접근기 없음 (0) | 2023.04.02 |
---|---|
WooCommerce 미니카트를 WordPress 사이트에 표시할 수 있는 방법이 있습니까? (0) | 2023.04.02 |
Flask RESTful 교차 도메인 문제 Angular: PUT, OPTIONS 메서드 (0) | 2023.04.02 |
Python에서 다소 잘못된 JSON을 해석하는 방법은 무엇입니까? (0) | 2023.04.02 |
WordPress에 등록한 후 코어 php로 자동 로그인하는 방법 (0) | 2023.04.02 |