프로젝트/날씨 칵테일

[프로젝트] 날씨 칵테일 | 트러블슈팅- 'AsyncThunkAction 형식의 인수는 'AnyAction' 형식의 매개 변수에 할당될 수 없습니다.'

paintover23 2023. 10. 13. 09:57
728x90

 

(진행배경) GetCocktail 컴포넌트 내부에서 dispatch를 사용하자 fetchCocktail(weatherName) 부분에서 'AsyncThunkAction<Cocktail, string, AsyncThunkConfig>' 형식의 인수는'AnyAction' 형식의 매개 변수에 할당될 없다는 타입에러가 발생하였다. 다음은 컴포넌트의 코드와 문제가 발생한 fetchCocktail 함수가 포함된 cocktailSlice 파일의 코드이다:

// GetCocktail.tsx

function GetCocktail({ weatherName }: GetCocktailProps) {
 
  const { cocktailInfo, status } = useSelector(
    (state: RootState) => state.cocktail
    );
  const dispatch = useDispatch();

  // action dispatch 하기
  useEffect(() => {
    if (weatherName) {
      dispatch(fetchCocktail(weatherName));
    }
  }, [dispatch, weatherName]); 

  return (
  // 중략..
  )
  }
// cocktailSlice.ts

export const fetchCocktail = createAsyncThunk<Cocktail, string>(
  'cocktail/fetchCocktail',
  async (weatherName) => {
  // 중략..
    }
  )​

 

[문제- 'AsyncThunkAction 형식의 인수는 'AnyAction' 형식의 매개 변수에 할당될 수 없습니다.'  에러]

(문제원인) Redux의 store.dispatch 메서드는 기본적으로 Redux의 'AnyAction' 타입을 기대한다. 반면 비동기 작업을 처리하는 fetchCocktail 함수의 createAsyncThunk(thunk action creators)는 'AsyncThunkAction'이라는 특수한 타입의 액션을 반환한다. 때문에 이는 기대되는 반환 값이 달라 발생하는 문제이다. 즉 AnyAction 타입을 기대하는 데 AsyncThunkAction 타입을 받아서 에러가 발생한 것이다.


dispatch(fetchCocktail(weatherName)) 에서, 

dispatch -> AnyAction 타입을 기대

fetchCocktail(createAsyncThunk)-> AsyncThunkAction 타입을 기대


(해결방법) 해결방법은 const dispatch = useDispatch에서 반환되는 함수의 타입을 명시적으로 AppDispatch로 지정하는 것이다. 이렇게 하면, dispatch 함수는 thunk action creators에서 반환되는 액션들도 처리할 수 있게 된다. 

// store.ts

// 중략...
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

위의 AppDispatch type을 import 하여 <AppDispatch> 라는 타입을 명시하는 방식으로 아래와 같이 작성하면 된다:

const dispatch = useDispatch<AppDispatch>

그런데 이전 포스트에서 useDispatch와 useSelector의 hook을 각각 useAppDispatch와 useAppSelector로 아래와 같이 정의했었기 때문에 이를 고려하여 대신 이렇게 작성할 수 있다:

// hooks.ts

export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
// GetCocktail.tsx

import { useAppSelector, useAppDispatch } from '../../../app/hooks';

function GetCocktail({ weatherName }: GetCocktailProps) {
  const { cocktailInfo, status } = useAppSelector((state) => state.cocktail); // useAppSelector
  const dispatch = useAppDispatch(); // useAppDispatch

  // action dispatch 하기
  useEffect(() => {
    if (weatherName) {
      dispatch(fetchCocktail(weatherName));
    }
  }, [dispatch, weatherName]);

// 중략..

 

(배운점) dispatch가 반환하는 타입과 createAsyncThunk 반환하는 타입에 대해 알게 되어 타입에러에 대응할 수 있게 되었다. createAsyncThunk는 비동기이기 때문에 dispatch 인자로 동기 함수를 받으면 문제는 발생하지 않을 것이다. 동기와 비동기를 구분하여 타입 에러 처리를 적절히 할 수 있어야 겠다.

728x90
반응형