[reactjs] 반응 후크에서`setState` 콜백을 사용하는 방법
React hooks는 useState
구성 요소 상태를 설정하기 위해 도입 되었습니다. 그러나 후크를 사용하여 아래 코드와 같이 콜백을 대체하려면 어떻게해야합니까?
setState(
{ name: "Michael" },
() => console.log(this.state)
);
상태가 업데이트 된 후에 뭔가를하고 싶습니다.
useEffect
추가 작업을 수행하는 데 사용할 수 있지만 비트 코드가 필요한 이전 상태 값을 확인해야합니다. useState
후크 와 함께 사용할 수있는 간단한 솔루션을 찾고 있습니다 .
답변
이를 위해서는 useEffect
후크를 사용해야합니다.
const [counter, setCounter] = useState(0);
const doSomething = () => {
setCounter(123);
}
useEffect(() => {
console.log('Do something after counter has changed', counter);
}, [counter]);
답변
이전 상태를 업데이트하려면 후크에서 다음과 같이 할 수 있습니다.
const [count, setCount] = useState(0);
setCount(previousCount => previousCount + 1);
답변
useEffect
, 상태 업데이트 에서만 발생 합니다 .
const [state, setState] = useState({ name: "Michael" })
const isFirstRender = useRef(true)
useEffect(() => {
if (!isFirstRender.current) {
console.log(state) // do something after state has updated
}
}, [state])
useEffect(() => {
isFirstRender.current = false // toggle flag after first render/mounting
}, [])
위는 setState
콜백을 가장 잘 모방하고 초기 상태 에서는 실행되지 않습니다 . 여기에서 사용자 지정 후크를 추출 할 수 있습니다.
function useEffectUpdate(effect, deps) {
const isFirstRender = useRef(true)
useEffect(() => {
if (!isFirstRender.current) {
effect()
}
}, deps) // eslint-disable-line react-hooks/exhaustive-deps
useEffect(() => {
isFirstRender.current = false;
}, []);
}
// ... Usage inside component
useEffectUpdate(() => { console.log(state) }, [state])
답변
사용 useEffect
은 직관적 인 방법이 아니라고 생각 합니다.
나는 이것을 위해 래퍼를 만들었습니다. 이 커스텀 후크에서는 setState
매개 변수 대신 매개 변수로 콜백을 전송할 수 있습니다 useState
.
방금 Typescript 버전을 만들었습니다. 따라서 Javascript에서 이것을 사용해야하는 경우 코드에서 유형 표기법을 제거하십시오.
용법
const [state, setState] = useStateCallback(1);
setState(2, (n) => {
console.log(n) // 2
});
선언
import { SetStateAction, useCallback, useEffect, useRef, useState } from 'react';
type Callback<T> = (value?: T) => void;
type DispatchWithCallback<T> = (value: T, callback?: Callback<T>) => void;
function useStateCallback<T>(initialState: T | (() => T)): [T, DispatchWithCallback<SetStateAction<T>>] {
const [state, _setState] = useState(initialState);
const callbackRef = useRef<Callback<T>>();
const isFirstCallbackCall = useRef<boolean>(true);
const setState = useCallback((setStateAction: SetStateAction<T>, callback?: Callback<T>): void => {
callbackRef.current = callback;
_setState(setStateAction);
}, []);
useEffect(() => {
if (isFirstCallbackCall.current) {
isFirstCallbackCall.current = false;
return;
}
callbackRef.current?.(state);
}, [state]);
return [state, setState];
}
export default useStateCallback;
약점
전달 된 화살표 함수가 변수 외부 함수를 참조하는 경우 상태가 업데이트 된 후 값이 아닌 현재 값을 캡처합니다. 위의 사용 예에서 console.log (state) 는 2가 아닌 1을 인쇄합니다.
답변
setState()
컴포넌트 상태의 변경 사항을 대기열에 추가하고이 컴포넌트와 그 자식을 업데이트 된 상태로 다시 렌더링해야한다고 React에 알립니다.
setState 메서드는 비동기 적이며 사실 약속을 반환하지 않습니다. 따라서 함수를 업데이트하거나 호출하려는 경우 setState 함수에서 두 번째 인수로 해당 함수를 콜백이라고 부를 수 있습니다. 예를 들어, 위의 경우 함수를 setState 콜백으로 호출했습니다.
setState(
{ name: "Michael" },
() => console.log(this.state)
);
위의 코드는 클래스 컴포넌트에 대해 잘 작동하지만 함수 컴포넌트의 경우 setState 메소드를 사용할 수 없으며 동일한 결과를 얻기 위해 use effect hook을 사용할 수 있습니다.
분명한 방법은 ypu가 useEffect와 함께 사용할 수 있다는 것입니다.
const [state, setState] = useState({ name: "Michael" })
useEffect(() => {
console.log(state) // do something after state has updated
}, [state])
그러나 이것은 첫 번째 렌더링에서도 발생하므로 첫 번째 렌더링 이벤트를 확인하고 상태 렌더링을 피할 수있는 코드를 다음과 같이 변경할 수 있습니다. 따라서 구현은 다음과 같은 방법으로 수행 할 수 있습니다.
여기에서 사용자 후크를 사용하여 첫 번째 렌더링을 식별 할 수 있습니다.
useRef 후크를 사용하면 기능적 구성 요소에서 가변 변수를 만들 수 있습니다. DOM 노드 / React 요소에 액세스하고 다시 렌더링을 트리거하지 않고 변경 가능한 변수를 저장하는 데 유용합니다.
const [state, setState] = useState({ name: "Michael" });
const firstTimeRender = useRef(true);
useEffect(() => {
if (!firstTimeRender.current) {
console.log(state);
}
}, [state])
useEffect(() => {
firstTimeRender.current = false
}, [])
답변
내 설정에서 useEffect를 사용하여 동일한 문제가 발생했습니다 (배열 여러 하위 구성 요소에서 부모의 상태를 업데이트하고 어떤 구성 요소가 데이터를 업데이트했는지 알아야 함).
promise에 setState를 래핑하면 완료 후 임의의 작업을 트리거 할 수 있습니다.
import React, {useState} from 'react'
function App() {
const [count, setCount] = useState(0)
function handleClick(){
Promise.resolve()
.then(() => { setCount(count => count+1)})
.then(() => console.log(count))
}
return (
<button onClick= {handleClick}> Increase counter </button>
)
}
export default App;
다음 질문은 저를 올바른 방향으로 인도합니다.
후크를 사용할 때 React 배치 상태가 업데이트됩니까?
답변
귀하의 질문은 매우 유효합니다. useEffect가 기본적으로 한 번 실행되고 종속성 배열이 변경 될 때마다 실행된다는 점을 말씀 드리겠습니다.
아래 예를 확인하십시오. :
import React,{ useEffect, useState } from "react";
const App = () => {
const [age, setAge] = useState(0);
const [ageFlag, setAgeFlag] = useState(false);
const updateAge = ()=>{
setAgeFlag(false);
setAge(age+1);
setAgeFlag(true);
};
useEffect(() => {
if(!ageFlag){
console.log('effect called without change - by default');
}
else{
console.log('effect called with change ');
}
}, [ageFlag,age]);
return (
<form>
<h2>hooks demo effect.....</h2>
{age}
<button onClick={updateAge}>Text</button>
</form>
);
}
export default App;
후크와 함께 setState 콜백을 실행하려면 플래그 변수를 사용하고 useEffect 내부에 IF ELSE OR IF 블록을 제공하여 해당 조건이 충족되면 해당 코드 블록 만 실행되도록합니다. 그러나 시간 효과는 종속성 배열 변경으로 실행되지만 효과 내부의 IF 코드는 해당 특정 조건에서만 실행됩니다.