React 16.7-alpha에서 새로운 후크 시스템을 가지고 놀았고 내가 처리중인 상태가 객체 또는 배열 일 때 useEffect에서 무한 루프에 갇혀 있습니다.
먼저 useState를 사용하고 다음과 같은 빈 개체로 시작합니다.
const [obj, setObj] = useState({});
그런 다음 useEffect에서 setObj를 사용하여 다시 빈 개체로 설정합니다. 두 번째 인수로 객체 의 내용 이 변경되지 않은 경우 업데이트되지 않기를 바라면서 [obj]를 전달 합니다. 하지만 계속 업데이트됩니다. 내용에 관계없이 항상 다른 객체이기 때문에 React가 계속 변한다고 생각합니까?
useEffect(() => {
setIngredients({});
}, [ingredients]);
배열의 경우도 마찬가지지만, 기본적으로 예상대로 루프에 갇히지 않습니다.
이러한 새로운 후크를 사용하여 콘텐츠가 변경되었는지 여부를 확인할 때 객체 및 배열을 어떻게 처리해야합니까?
답변
빈 배열을 useEffect의 두 번째 인수로 전달하면 마운트 및 마운트 해제시에만 실행되므로 무한 루프가 중지됩니다.
useEffect(() => {
setIngredients({});
}, []);
이것은 https://www.robinwieruch.de/react-hooks/의 React hooks에 대한 블로그 게시물에서 저에게 명확 해졌습니다.
답변
같은 문제가있었습니다. 왜 그들이 문서에서 이것을 언급하지 않았는지 모르겠습니다. Tobias Haugen 답변에 약간을 추가하고 싶습니다.
모든 구성 요소 / 상위 rerender 에서 실행하려면 다음 을 사용해야합니다.
useEffect(() => {
// don't know where it can be used :/
})
컴포넌트 마운트 후 한 번만 실행하려면 (한 번 렌더링 됨) 다음을 사용해야합니다.
useEffect(() => {
// do anything only one time if you pass empty array []
// keep in mind, that component will be rendered one time (with default values) before we get here
}, [] )
구성 요소 마운트 및 데이터 / 데이터 2 변경 시 한 번만 실행하려면 :
const [data, setData] = useState(false)
const [data2, setData2] = useState('default value for first render')
useEffect(() => {
// if you pass some variable, than component will rerender after component mount one time and second time if this(in my case data or data2) is changed
// if your data is object and you want to trigger this when property of object changed, clone object like this let clone = JSON.parse(JSON.stringify(data)), change it clone.prop = 2 and setData(clone).
// if you do like this 'data.prop=2' without cloning useEffect will not be triggered, because link to data object in momory doesn't changed, even if object changed (as i understand this)
}, [data, data2] )
대부분의 시간 사용 방법 :
export default function Book({id}) {
const [book, bookSet] = useState(false)
useEffect(() => {
loadBookFromServer()
}, [id]) // every time id changed, new book will be loaded
// Remeber that it's not always safe to omit functions from the list of dependencies. Explained in comments.
async function loadBookFromServer() {
let response = await fetch('api/book/' + id)
response = await response.json()
bookSet(response)
}
if (!book) return false //first render, when useEffect did't triggered yet we will return false
return <div>{JSON.stringify(book)}</div>
}
답변
같은 문제가 한 번도 발생했고 두 번째 인수에 기본 값을 전달하여 문제를 해결했습니다 []
.
객체를 전달하면 React는 객체에 대한 참조 만 저장하고 참조가 변경 될 때 효과를 실행합니다. 이는 일반적으로 매번 매번 발생합니다 (지금은 그렇지 않습니다).
해결책은 객체의 값을 전달하는 것입니다. 당신은 시도 할 수 있습니다,
const obj = { keyA: 'a', keyB: 'b' }
useEffect(() => {
// do something
}, [Object.values(obj)]);
또는
const obj = { keyA: 'a', keyB: 'b' }
useEffect(() => {
// do something
}, [obj.keyA, obj.keyB]);
답변
문서 ( https://reactjs.org/docs/hooks-effect.html ) 에서 말했듯 이 useEffect
후크는 렌더링 할 때마다 일부 코드가 실행되기를 원할 때 사용 됩니다 . 문서에서 :
useEffect는 모든 렌더링 후에 실행됩니까? 예!
이를 사용자 정의하려면 나중에 동일한 페이지 ( https://reactjs.org/docs/hooks-effect.html#tip-optimizing-performance-by-skipping-effects ) 에 표시되는 지침을 따를 수 있습니다 . 기본적으로이 useEffect
메서드는 React가 효과를 다시 트리거해야하는지 여부를 결정하기 위해 조사 할 두 번째 인수를 받습니다 .
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only re-run the effect if count changes
두 번째 인수로 모든 개체를 전달할 수 있습니다. 이 개체가 변경되지 않으면 효과는 첫 번째 탈것 이후에만 발동 됩니다. 개체가 변경되면 효과가 다시 트리거됩니다.
답변
사용자 정의 후크를 구축하는 경우 다음과 같이 기본값으로 무한 루프가 발생할 수 있습니다.
function useMyBadHook(values = {}) {
useEffect(()=> {
/* This runs every render, if values is undefined */
},
[values]
)
}
수정 사항은 모든 함수 호출에서 새 객체를 만드는 대신 동일한 객체를 사용하는 것입니다.
const defaultValues = {};
function useMyBadHook(values = defaultValues) {
useEffect(()=> {
/* This runs on first call and when values change */
},
[values]
)
}
구성 요소 코드에서이 문제가 발생 하면 ES6 기본값 대신 defaultProps를 사용하면 루프가 수정 될 수 있습니다.
function MyComponent({values}) {
useEffect(()=> {
/* do stuff*/
},[values]
)
return null; /* stuff */
}
MyComponent.defaultProps = {
values = {}
}
답변
이것이 효과가 있는지 확실하지 않지만 다음과 같이 .length를 추가해 볼 수 있습니다.
useEffect(() => {
// fetch from server and set as obj
}, [obj.length]);
제 경우에는 (배열을 가져 왔습니다!) 마운트시 데이터를 가져 왔고 변경시에만 데이터를 가져 왔고 루프에 들어 가지 않았습니다.
답변
useEffect 끝에 빈 배열을 포함하는 경우 :
useEffect(()=>{
setText(text);
},[])
한 번 실행됩니다.
배열에 매개 변수도 포함하는 경우 :
useEffect(()=>{
setText(text);
},[text])
텍스트 매개 변수가 변경 될 때마다 실행됩니다.