리액트 훅에서 'setState' 콜백을 사용하는 방법
에 의해 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]);
「 」를 useEffect
첫 번째 렌더링 시 무시되는 콜백에 따라 코드를 수정합니다.
import React, { useEffect, useRef } from 'react';
const [counter, setCounter] = useState(0);
const didMount = useRef(false);
const doSomething = () => {
setCounter(123);
}
useEffect(() => {
// Return early, if this is the first render:
if ( !didMount.current ) {
return didMount.current = true;
}
// Paste code to be executed on subsequent renders:
console.log('Do something after counter has changed', counter);
}, [counter]);
이전 상태를 갱신하는 경우는, 훅으로 다음과 같이 할 수 있습니다.
const [count, setCount] = useState(0);
setCount(previousCount => previousCount + 1);
setState
에 「」을 부가합니다.useEffect
, 상태 갱신시에만 기동합니다(초기 상태는 기동하지 않습니다.
const [state, setState] = useState({ name: "Michael" })
const isFirstRender = useRef(true)
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false // toggle flag after first render/mounting
return;
}
console.log(state) // do something after state has updated
}, [state])
훅useEffectUpdate
function useEffectUpdate(callback) {
const isFirstRender = useRef(true);
useEffect(() => {
if (isFirstRender.current) {
isFirstRender.current = false; // toggle flag after first render/mounting
return;
}
callback(); // performing action after state has updated
}, [callback]);
}
// client usage, given some state dep
const cb = useCallback(() => { console.log(state) }, [state]); // memoize callback
useEffectUpdate(cb);
생각에는, 내에, 용 i를 useEffect
직관적인 방법이 아닙니다.
이거 포장지를 만들었어요.훅에서는, 을 「 」, 「 」에 할 수 .setState
parameter를 합니다.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을 인쇄합니다.
셋업에서 useEffect를 사용해도 문제가 해결되지 않았습니다(어레이의 여러 하위 컴포넌트에서 부모 상태를 업데이트하고 있는데 어떤 컴포넌트가 데이터를 업데이트했는지 알아야 합니다).
약속으로 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 batch state update가 기능합니까?
아직 필요한 사람이 있으면 타이프로 커스텀 훅을 작성했습니다.
import React, { useEffect, useRef, useState } from "react";
export const useStateWithCallback = <T>(initialState: T): [state: T, setState: (updatedState: React.SetStateAction<T>, callback?: (updatedState: T) => void) => void] => {
const [state, setState] = useState<T>(initialState);
const callbackRef = useRef<(updated: T) => void>();
const handleSetState = (updatedState: React.SetStateAction<T>, callback?: (updatedState: T) => void) => {
callbackRef.current = callback;
setState(updatedState);
};
useEffect(() => {
if (typeof callbackRef.current === "function") {
callbackRef.current(state);
callbackRef.current = undefined;
}
}, [state]);
return [state, handleSetState];
}
setState()
는 컴포넌트 상태에 대한 변경을 큐잉하고 React에게 이 컴포넌트와 그 하위 컴포넌트를 업데이트된 상태로 재렌더링해야 함을 알립니다.
setState 메서드는 비동기식으로 실제로는 약속을 반환하지 않습니다.따라서 함수를 업데이트 또는 호출하는 경우 setState 함수의 함수를 두 번째 인수로 콜백할 수 있습니다.예를 들어 위의 경우 함수를 setState 콜백으로 호출했습니다.
setState(
{ name: "Michael" },
() => console.log(this.state)
);
위의 코드는 클래스 컴포넌트에서는 정상적으로 동작하지만 기능 컴포넌트의 경우 setState 메서드를 사용할 수 없습니다.이것에 의해, use effect use effect 훅을 사용할 수 있습니다.
ypu를 useEffect와 함께 사용할 수 있는 명백한 방법은 다음과 같습니다.
const [state, setState] = useState({ name: "Michael" })
useEffect(() => {
console.log(state) // do something after state has updated
}, [state])
그러나 첫 번째 렌더링에서도 실행되므로 첫 번째 렌더링 이벤트를 확인하고 상태 렌더링을 피할 수 있는 코드를 다음과 같이 변경할 수 있습니다.그 때문에, 실장은 다음의 방법으로 실시할 수 있습니다.
여기서 사용자 후크를 사용하여 첫 번째 렌더를 식별할 수 있습니다.
useRef Hook을 사용하면 기능 컴포넌트에 가변 변수를 만들 수 있습니다.이 기능은 DOM 노드/React 요소에 액세스하여 재렌더를 트리거하지 않고 가변 변수를 저장하는 데 유용합니다.
const [state, setState] = useState({ name: "Michael" });
const firstTimeRender = useRef(true);
useEffect(() => {
if (!firstTimeRender.current) {
console.log(state);
}
}, [state])
useEffect(() => {
firstTimeRender.current = false
}, [])
업데이트 후 최신 상태를 얻으려면 다음과 같은 방법을 사용할 수 있습니다.
const [state, setState] = useState({name: "Michael"});
const handleChangeName = () => {
setState({name: "Jack"});
}
useEffect(() => {
console.log(state.name); //"Jack"
//do something here
}, [state]);
- (기능 업데이트)
https://reactjs.org/docs/hooks-reference.html#functional-updateshttpsreactjs.org/docs/hooks-reference.html#
상태를 하여 새 할 수 ."이전 상태를 사용하여 새로운 상태를 계산하면 함수를 setState에 전달할 수 있습니다.
const [state, setState] = useState({name: "Michael"});
const handleChangeName = () => {
setState({name: "Jack"})
setState(prevState => {
console.log(prevState.name);//"Jack"
//do something here
// return updated state
return prevState;
});
}
const [state, setState] = useState({name: "Michael"});
const stateRef = useRef(state);
stateRef.current = state;
const handleClick = () => {
setState({name: "Jack"});
setTimeout(() => {
//it refers to old state object
console.log(state.name);// "Michael";
//out of syntheticEvent and after batch update
console.log(stateRef.current.name);//"Jack"
//do something here
}, 0);
}
에 모든 상태 됩니다.react syntheticEvent setState는 setState를 반환합니다.
는 항상컴포넌트를 하지 않습니다."setState()는 컴포넌트를 즉시 업데이트하지 않습니다. ",
https://reactjs.org/docs/react-component.html#setstatehttpsreactjs.org/docs/.html#setstate
상태 설정 후 몇 가지 파라미터로 API 호출을 하고 싶은 유스케이스가 있었습니다.이러한 파라미터를 자신의 상태로 설정하고 싶지 않기 때문에 커스텀 훅을 만들었습니다.이것이 해결책입니다.
import { useState, useCallback, useRef, useEffect } from 'react';
import _isFunction from 'lodash/isFunction';
import _noop from 'lodash/noop';
export const useStateWithCallback = initialState => {
const [state, setState] = useState(initialState);
const callbackRef = useRef(_noop);
const handleStateChange = useCallback((updatedState, callback) => {
setState(updatedState);
if (_isFunction(callback)) callbackRef.current = callback;
}, []);
useEffect(() => {
callbackRef.current();
callbackRef.current = _noop; // to clear the callback after it is executed
}, [state]);
return [state, handleStateChange];
};
당신의 질문은 매우 타당합니다.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 콜백을 훅과 함께 실행하는 경우 flag 변수를 사용하여 useEffect 내의 IF ELSE 또는 IF 블록을 지정합니다.이 조건이 충족되면 해당 코드 블록만 실행됩니다.의존관계 배열의 변경에 따라 시간 효과가 실행되지만 IF 코드 내부 효과는 해당 특정 조건에 대해서만 실행됩니다.
훅을 쓸 수 있어요useScheduleNextRenderCallback
이 명령어는 "syslog" 함수를 반환합니다.전화하고 나서setState
다음 렌더링에서 실행할 콜백을 전달하여 "callback" 함수를 호출할 수 있습니다.
import { useCallback, useEffect, useRef } from "react";
type ScheduledCallback = () => void;
export const useScheduleNextRenderCallback = () => {
const ref = useRef<ScheduledCallback>();
useEffect(() => {
if (ref.current !== undefined) {
ref.current();
ref.current = undefined;
}
});
const schedule = useCallback((fn: ScheduledCallback) => {
ref.current = fn;
}, []);
return schedule;
};
사용 예:
const App = () => {
const scheduleNextRenderCallback = useScheduleNextRenderCallback();
const [state, setState] = useState(0);
const onClick = useCallback(() => {
setState(state => state + 1);
scheduleNextRenderCallback(() => {
console.log("next render");
});
}, []);
return <button onClick={onClick}>click me to update state</button>;
};
테스트 케이스 축소: https://stackblitz.com/edit/react-ts-rjd9jk
심플한 솔루션, 설치만 하면 됩니다.
npm i use-state-with-callback
import React from 'react';
import { useStateWithCallbackLazy } from "use-state-with-callback";
const initialFilters = {
smart_filter: "",
};
const MyCallBackComp = () => {
const [filters, setFilters] = useStateWithCallbackLazy(initialFilters);
const filterSearchHandle = (e) => {
setFilters(
{
...filters,
smart_filter: e,
},
(value) => console.log("smartFilters:>", value)
);
};
return (
<Input
type="text"
onChange={(e) => filterSearchHandle(e.target.value)}
name="filter"
placeholder="Search any thing..."
/>
);
};
편집필
여기서 약속을 사용하면 재렌더 후 실행이 지연되고 트리거가 발생합니다.setState
최신 상태를 얻으려면 두 번이 가장 좋은 해결책일 수 있습니다.왜냐하면 setState가 리스트 되기 때문에prevState
사용할 수 있습니다.
오리지널 투고
Promise
「 setState 」 、「 setState 。
여기 내 실험 결과야, 콜백을 사용하는 것보다 기분이 좋아
해결 하여 에서 .useEffect
function useAsyncState(initialState) {
const [state, setState] = useState(initialState)
const resolveCb = useRef()
const handleSetState = (updatedState) => new Promise((resolve, reject) => {
// force previous promise resolved
if (typeof resolveCb.current === 'function') {
resolveCb.current(updatedState)
}
resolveCb.current = resolve
try {
setState(updatedState)
} catch(err) {
resolveCb.current = undefined
reject(err)
}
})
useEffect(() => {
if (typeof resolveCb.current === 'function') {
resolveCb.current(state)
resolveCb.current = undefined
}
}, [state])
return [state, handleSetState]
}
컴포넌트에서 사용
function App() {
const [count, setCount] = useAsyncState(0)
const increment = useMemoizedFn(async () => {
const newCount = await setCount(count + 1)
console.log(newCount)
})
console.log('rerender')
return (
<div>
<h3 onClick={increment}>Hi, {count}</h3>
</div>
)
}
useRef를 사용하여 마운트되었는지 아닌지를 구별하는 것은 좋은 방법이 아니라고 생각합니다만, useEffect()의 genated useState() 값을 초기값인지 아닌지를 결정하는 것이 더 좋은 방법이 아닐까요?
const [val, setVal] = useState(null)
useEffect(() => {
if (val === null) return
console.log('not mounted, val updated', val)
}, [val])
setState 콜백을 네이티브로 지원할 때까지 플레인 javascript 방식으로 함수를 호출하여 새로운 변수를 직접 전달합니다.
const [counter, setCounter] = useState(0);
const doSomething = () => {
const newCounter = 123
setCounter(newCounter);
doSomethingWCounter(newCounter);
};
function doSomethingWCounter(newCounter) {
console.log(newCounter); // 123
}
없는 는, 「Ref」 에 「를할 수 .useState
.
const name = useRef("John");
name.current = "Michael";
console.log(name.current); // will print "Michael" since updating the ref is not async
use-state-with-callback npm 라이브러리 및 기타 유사한 커스텀훅에 대해 알아보았지만, 결국 다음과 같은 작업을 수행할 수 있다는 것을 깨달았습니다.
const [user, setUser] = React.useState(
{firstName: 'joe', lastName: 'schmo'}
)
const handleFirstNameChange=(val)=> {
const updatedUser = {
...user,
firstName: val
}
setUser(updatedUser)
updateDatabase(updatedUser)
}
돔에서 클래스를 렌더링하고 다른 클래스를 설정해야 하는 매우 구체적인 사용 사례가 있습니다.이것이 내가 꽤 우아하다고 생각한 나의 해결책이었다.
const [value1, setValue1] = useState({value: 'whatever', onValue: false})
useEffect(() => {
setValue1(prev => ({
value: 'whatever',
onValue: !prev.onValue,
}));
}, ['whatever'])
useEffect(() => {
// if you want to ensure the render happens before doThing2() then put it in a timeout of 1ms,
setTimeout(doThing2, 1);
// or if you are happy to call it immediately after setting value don't include the timeout
doThing2()
}, [value1.onValue])
함수를 통과시키는 건 어때?
const [name, setName] = useState(initialName);
...
setName(() => {
const nextName = "Michael";
console.log(nextName);
return nextName;
});
에게 은 ★★★★★★★★★★★★★★★★★★★★★★★★★★★」useState
★★★★★★★★★★★★★★★★★」useCallback
:
코드 예시
import React, { useCallback, useState } from 'react';
const Test = () => {
const [name, setName] = useState("");
const testCallback = useCallback(() => console.log(name), [name]);
return (
<button onClick={() => {
setName("Michael")
testCallback();
}}>Name</button>
)
};
export default Test;
이거 어때:
const [Name, setName] = useState("");
...
onClick={()=>{
setName("Michael")
setName(prevName=>{...}) //prevName is Michael?
}}
UseEffect가 주요 솔루션입니다.그러나 Darryl이 설명한 바와 같이 useEffect를 사용하고 두 번째 파라미터로 상태를 전달하면 하나의 결함이 있습니다.이 컴포넌트는 초기화 프로세스에서 실행됩니다.콜백 함수가 갱신된 상태의 값을 사용하여 실행되도록 하는 경우 로컬 상수를 설정하고 setState와 콜백 모두에서 사용할 수 있습니다.
const [counter, setCounter] = useState(0);
const doSomething = () => {
const updatedNumber = 123;
setCounter(updatedNumber);
// now you can "do something" with updatedNumber and don't have to worry about the async nature of setState!
console.log(updatedNumber);
}
언급URL : https://stackoverflow.com/questions/56247433/how-to-use-setstate-callback-on-react-hooks
'programing' 카테고리의 다른 글
Spring MVC 명령어개체를 바인드할 때 파라미터 이름을 커스터마이즈하려면 어떻게 해야 합니까? (0) | 2023.02.27 |
---|---|
wordpress에서 $wpdb를 사용하여 SQL 명령 실행 (0) | 2023.02.27 |
JSON 개체를 파일에 저장하는 중입니다.JSON (0) | 2023.02.27 |
열 데이터 유형의 바이트와 CHAR의 차이 (0) | 2023.02.27 |
Angular에서 스코프 변수가 정의되지 않았는지 확인하는 방법JS 템플릿? (0) | 2023.02.27 |