useEffect 에서 비동기 처리 방식들의 차이. 안에서 함수를 선언하고 호출하는 것과.. 밖에서 정의하고 호출하는 것과 .. 등등
: useEffect 내부에서 함수로 감싸서(선언해서) call 하는 것과 예를 들어 그냥 바로 axios 요청하는 것과 차이
index.js:1 Warning: **An effect function must not return anything besides a function, which is used for clean-up.**
It looks like you wrote useEffect(async () => ...) or returned a Promise. Instead, **write the async function inside your effect and call it immediately**:
useEffect(() => {
async function fetchData() {
// You can await here
const response = await MyAPI.getData(someId);
// ...
}
fetchData();
}, [someId]); // Or [] if effect doesn't need props or state
Learn more about data fetching with Hooks: https://fb.me/react-hooks-data-fetching
in App (at src/index.js:9)
in Router (created by BrowserRouter)
in BrowserRouter (at src/index.js:8)
위와 같이 Warning이 뜸. async + await 로 비동기 제어해주고 fetchData() 이런 식으로 함수를 호출(실행)해주는 형태를 권고함
async 함수는 promise 객체를 리턴함(implicit), 그러나 effect hook은 아무것도 리턴하지 않거나 clean up 함수 자체를 리턴해야 하므로, 바로 async 함수를 작성하지 않고 함수를 내부에서 정의해서 call하는 것임
🔗 참고 링크 🌟 *good!
정리
[]
에 의해 무한히 useEffect 가 호출될 수 있음(component가 update될 때마다)[]
비어 있을 때만 최초 렌더 시 (when component mounts) fetch해 온다.결론
- async함수는 비동기함수 객체 즉 promise 객체를 리턴함.(implicit promise)
- effect hook은 아무것도 반환하지 않거나 clean up 함수를 리턴해야 함
- 그래서 이런 오류가 뜨는 것이고, async함수를 useEffect에서 바로 사용하지 말라고 warning이 뜨는 것.
원문
The effect hook called useEffect is used to fetch the data with axios from the API and to set the data in the local state of the component with the state hook's update function. The promise resolving happens with async/await.
However, when you run your application, you should stumble into a nasty loop. The effect hook runs when the component mounts but also when the component updates. Because we are setting the state after every data fetch, the component updates and the effect runs again. It fetches the data again and again. That's a bug and needs to be avoided. We only want to fetch data when the component mounts. That's why you can provide an empty array as second argument to the effect hook to avoid activating it on component updates but only for the mounting of the component.
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(**async** () => {
const result = **await** axios(
'https://hn.algolia.com/api/v1/search?query=redux',
);
setData(result.data);
}, **[]**);
The second argument can be used to define all the variables (allocated in this array) on which the hook depends. If one of the variables changes, the hook runs again. If the array with the variables is empty, the hook doesn't run when updating the component at all, because it doesn't have to watch any variables.
There is one last catch. In the code, we are using async/await to fetch data from a third-party API. According to the documentation every function annotated with async returns an implicit promise: "The async function declaration defines an asynchronous function, which returns an AsyncFunction object. An asynchronous function is a function which operates asynchronously via the event loop, using an implicit Promise to return its result. ". However, an effect hook should return nothing or a clean up function. That's why you may see the following warning in your developer console log: 07:41:22.910 index.js:1452 Warning: useEffect function must return a cleanup function or nothing. Promises and useEffect(async () => ...) are not supported, but you can call an async function inside an effect.. That's why using async directly in the useEffect
function isn't allowed. Let's implement a workaround for it, by using the async function inside the effect.
function App() {
const [data, setData] = useState({ hits: [] });
useEffect(() => {
** const fetchData = async () => {**
const result = await axios(
'https://hn.algolia.com/api/v1/search?query=redux',
);
setData(result.data);
};
** fetchData();**
}, []);
const=()=>{}
)과 선언식(function(){}
) 의 차이는?useEffect 내부에서 함수를 정의하는 이유*효과
1. 외부에 정의 시 useCallback으로 감싸야 함
2. 렌더 할 때마다 함수가 선언될 필요가 없다. useEffect 에서만 사용하는 함수라면 특히.
3. useEffect 내부에서 변수나 함수를 선언함으로써 비동기 제어+ cleanup이 더 쉬움.
🔗 참고 링크(스택오버플로우)
Why do we define function inside useEffect?
: reasons
On that last one, for instance, you can do some actions to prevent state being called when the effect cleans up.
주의 arrow function (const functionname = () ⇒ {}
*표현식 + arrow ) 는 hositing 되지 않음!
handleLogout 정의 시 선언식 으로. (function name () {}
)
*useEffect 내부에서 선언식으로 표현식으로 하는 것의 차이? 스코프 차이인가?
선언식은 호이스팅되면서 전역변수화?
es6 이후로 sugar syntax 되어 상관없다고 함, same scope를 가짐!
리액트 hook은 기본적으로 순수함수(형 컴포넌트)에서 쓸 수 있음을 기억
🔗 참고 공식문서
cleanup이 필요한 side effect 의 경우, 메모리 누수를 방지하기 위해 clean up 함수 필요
important to clean up so that we don’t introduce a memory leak
clean up 이라 함은 useEffect 내 return 이 있는 것
외부로부터 데이터를 구독하는 경우? (set up a subscription to some external data source)
클래스 컴포넌트의 경우
componentWillUnmount
로 clean up을 처리함(componentDidMount
에서 외부데이터리소스 구독을 처리하고)
*Lifecycle methods force us to split this logic even though conceptually code in both of them is related to the same effect.
by using Hooks
useEffect Hook 자체가 두 상황?을 다룰 수 있도록 고안됨
: (구독 해제-componentWillUnmount
구독 처리-componentDidMount
의 경우)
‣subscription 추가, 제거 코드는 결합도가 높기 때문에.
effect가 함수를 리턴하면 리액트는 cleanup 필요 시 그 함수를 실행함.
You might be thinking that we’d need a separate effect to perform the cleanup. But code for adding and removing a subscription is so tightly related that useEffect is designed to keep it together. If your effect returns a function, React will run it when it is time to clean up
컴포넌트가 unmount 될 때 또 한번의 effect 실행 전 이전 렌더에서의 effect를 지우는 것이다.
React performs the cleanup when the component unmounts. .. effects run for every render and not just once. This is why React also cleans up effects from the previous render before running the effects next time.
사실 componentDidUpdate 가 있어야 확실한 보완?이 됨 🔗 [참고][공식문서](https://reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update)
⇒ 클래스 컴포넌트에서 생길 수 있는 bug를 방지하고 consistency를 보장할 수 있는 방법임
*여기서 말하는 버그란: 컴포넌트가 뷰에 렌더된 상태에서 props값이 변동이 생겼을 때, 이전 데이터를 계속 보여주는 상태 일 수 있음. memory leak나 crash.
ensures consistency by default and prevents bugs that are common in class components due to missing update logic.
effect 발생 시나 cleanup 시에 이러한 버그 있을 수 있으므로, DidUpdate 에서 prevProps
나 prevState
를 사용해서 effect를 skip 하도록 처리하기도 ..
참고 링크(스택오버플로우)
You're returning the result of calling getResponse()
from the useEffect
function. If you return anything from useEffect
, it has to be a function. Changing your code to this should fix it because you're no longer returning anything from the useEffect
function.
useEffect(() => {
getResponse();
});
useEffect
Cleanup FunctionIf you return anything from the useEffect
hook function, it must be a cleanup function. This function will run when the component unmounts. This can be thought of as roughly equivalent to the componentWillUnmount
lifecycle method in class components.