죽밥이
848
2020-07-31 21:35:26 작성 2020-07-31 21:35:40 수정됨
7
403

리액트 훅에서 리덕스를 통해 상태 불러오는 방법 없을까요?


기존에는 useEffect 안에서 API를 호출하여 상태를 설정하는 방식이었습니다.

이걸 리액트 리덕스로 상태관리를 하려고 하는데 TypeError: data.map is not a function 오류가 발생합니다.

아래 기존코드와 변경한 코드 확인부탁드립니다.


* 기존 코드입니다.

// 기존 코드
useEffect(() => {
        post('/admin/adminList')
            .then(res => {
                setState({
                    values: res.data.list,
                    adminCnt: res.data.adminCnt
                });
            })
            .catch(err => {
                throw(err);
            });
}, []);

const callbackComponents = (data) => {
  return data.map((c, index) => {
            return <AdminListTable
                key={index} 
                index={index}
                adminId={c.adminId} email={c.email} name={c.name} phoneNo= 
                {c.phoneNo} createDt={c.createDt} useYn={c.useYn} secYn= 
                {c.secYn}
            />
        })
};

return (
<Table>
 {state.values ? callbackComponents(adminList.values) : null }
</Table>


* 리덕스로 불러온 코드입니다.

// 리덕스로 가져온 상태
const dispatch = useDispatch();

useEffect(() => {
        dispatch(getAdminListing());
}, [dispatch]);

const adminList = useSelector(state => state.adminList) || '';

// 이 펑션을 실행했을 때 data.map is not a function 오류가 발생합니다.
const callbackComponents = (data) => {
        console.log(data);
        return data.map((c, index) => {
            return <AdminListTable
                key={index} 
                index={index}
                adminId={c.adminId} email={c.email} name={c.name} phoneNo= 
                {c.phoneNo} createDt={c.createDt} useYn={c.useYn} secYn= 
                {c.secYn}
            />
        })
}

return (
<Table>
  {adminList.values ? callbackComponents(adminList.values) : null}
</Table>


오류가 나서 useEffect 안에 useSelector를 넣어보았는데 그것도 useSelector를 호출할 수 없다는 오류가 나타났습니다.

이런경우 어떻게 해결해야 할까요?ㅠㅠ


0
  • 답변 7

  • seacont
    82
    2020-07-31 23:09:51

    reducer내의 adminList.values의 초기값이 배열 타입으로 지정되어 있나요?

  • 죽밥이
    848
    2020-07-31 23:37:52

    답변주셔서 감사합니다.

    넵 배열타입으로 되어있습니다.

    혹시 모르니 reducer 내부 코드 첨부하겠습니다.

    import { GET_ADMINLIST } from '../actions/index';
    
    export default function (state = [], action) {
        switch (action.type) {
            case GET_ADMINLIST:
                return {
                    ...state,
                    values: action.data.list,
                    adminCnt: action.data.adminCnt
                } 
            default:
                return state;
        }
    }



  • 죽밥이
    848
    2020-07-31 23:44:09 작성 2020-07-31 23:45:37 수정됨

    seacont

    덕분에 힌트를 얻어 해결했습니다!!

    state 초기값을 빈문자열로 설정하니까 되네요!!

    감사합니다


    근데 궁금한점은.. 배열로 값이 들어오는거니까 빈배열로 초기값을 주는게 맞을텐데..

    왜 빈 문자열이어야 하는걸까요?

  • seacont
    82
    2020-07-31 23:50:32

    1. 위의 reducer 코드에서 state가 values를 의미한다면

    return {
      ...state,
      values: action.data.list,
      adminCnt: action.data.adminCnt
    };

    위의 코드는 아래와 같이 되어야 합니다.

    return [...state, ...action.data.list];


    2. 위의 reducer 코드에서 state가 adminList를 의미한다면

    export default function (state = [], action) {

    위의 코드는 아래와 같이 되어야 합니다.

    export default function (state = { values: [], adminCnt: 0 }, action) {


  • 죽밥이
    848
    2020-07-31 23:58:44

    아 그런 중요한 내용을 몰랐네요 ㅠㅠ

    덕분에 속이 시원해졌습니다~ 감사합니다!

  • seacont
    82
    2020-08-01 00:14:00

    도움이 되었다니 보람차네요! 개인적으로는 adminList의 초기값이 []인데 아래 코드에서 어떻게 callbackComponents()가 호출되었는지가 궁금했습니다.

    {adminList.values ? callbackComponents(adminList.values) : null}

    알고보니 자바스크립트 배열의 매소드 중에 values()가 있어서 [].values가 falsy하지 않다고 판정되었네요. 혹시나 참고하세요~

  • 죽밥이
    848
    2020-08-01 00:25:42

    아 그 부분도 생각을 못 했었네요 ㅠㅠ

    초기값이 배열이면 배열에 값이 있는지 검사했어야 하는거군요~

    추가적으로 도움주셔서 감사합니다!

  • 로그인을 하시면 답변을 등록할 수 있습니다.