⚛️ 기본 환경: IDE: VS code, Language: React

 

 

발생 Error

React에서 다음 Source Code를 실행할 경우,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { cat, chick, dog, tiger } from '../../store/modules/animal';
 
const Animal = () => {
    const name = useSelector(state => state.animal.name);
    // animal reducer 안의 name
    const crying = useSelector(state => state.animal.crying);
    const dispatch = useDispatch(); // action을 발생시키는 함수
 
    return (
        <div>
            <h1>동물의 울음소리</h1>
            <h1>{name} : {crying}</h1>
            <p>
                <button onClick={() => dispatch(tiger)}>호랑이</button>
                {/*
                dispatch(tiger): →
                index.js → 
                export const tiger = () => ({type: TIGER});
                */}
                <button onClick={() => dispatch(dog)}>강아지</button>
                <button onClick={() => dispatch(cat)}>고양이</button>
                <button onClick={() => dispatch(chick)}>병아리</button>
            </p>
        </div>
    );
};
 
export default Animal;
 
 
 

🚨 다음과 같은 오류 발생

Actions must be plain objects. Use custom middleware for async actions.

 

 

발생 원인

dispatch의 매개변수로 함수 포인터를 선언

 

 

해결 방법

dispatch의 매개변수를 객체로 선언

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { cat, chick, dog, tiger } from '../../store/modules/animal';
 
const Animal = () => {
    const name = useSelector(state => state.animal.name);
    // animal reducer 안의 name
    const crying = useSelector(state => state.animal.crying);
    const dispatch = useDispatch(); // action을 발생시키는 함수
 
    return (
        <div>
            <h1>동물의 울음소리</h1>
            <h1>{name} : {crying}</h1>
            <p>
                <button onClick={() => dispatch(tiger())}>호랑이</button>
                {/*
                dispatch(tiger): →
                index.js → 
                export const tiger = () => ({type: TIGER});
                */}
                <button onClick={() => dispatch(dog())}>강아지</button>
                <button onClick={() => dispatch(cat())}>고양이</button>
                <button onClick={() => dispatch(chick())}>병아리</button>
            </p>
        </div>
    );
};
 
export default Animal;
 
 
 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

발생 Error

React에서 다음 Source Code를 실행할 경우,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import classes from './CartButton.module.css';
 
import uiActions from '../../store/ui-slice'
import { useDispatch } from 'react-redux';
 
const CartButton = (props) => {
  const dispatch = useDispatch();
  
  const toggleCartHandler = () => {
    dispatch(uiActions.toggle());
  };
  
  return (
    <button className={classes.button} onClick={toggleCartHandler}>
      <span>My Cart</span>
      <span className={classes.badge}>1</span>
    </button>
  );
};
 
export default CartButton;
 
 
 

🚨 toggleCartHandler가 onClick 메서드로 걸린 버튼 클릭 시, 다음과 같은 오류 발생

TypeError: _store_ui_slice__WEBPACK_IMPORTED_MODULE_1__.default.toggle is not a function

 

 

발생 원인

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import { createSlice } from "@reduxjs/toolkit";
 
const uiSlice = createSlice({
    name'ui',
    initialState: {cartIsVisible: false},
    reducers: {
        toggle(state){
            state.cartIsVisible = !state.cartIsVisible;
        }
    },
});
 
export const uiActions = uiSlice.actions;
 
export default uiSlice;
 
 
 

uiSlice를 default로 export, uiActions는 개별 함수로 export

default로 export하지 않은 uiActions를 {}없이 import

 

 

해결 방법

⭐ export default로 내보낸 것만 중괄호 없이 import
이 외export 문은 중괄호를 사용하여 import

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import classes from './CartButton.module.css';
 
import {uiActions} from '../../store/ui-slice'
import { useDispatch } from 'react-redux';
 
const CartButton = (props) => {
  const dispatch = useDispatch();
  
  const toggleCartHandler = () => {
    dispatch(uiActions.toggle());
  };
  
  return (
    <button className={classes.button} onClick={toggleCartHandler}>
      <span>My Cart</span>
      <span className={classes.badge}>1</span>
    </button>
  );
};
 
export default CartButton;
 
 
 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

발생 Error

React에서 다음 Source Code를 실행할 경우,

1
2
import { createSlice } from "@reduxjs/toolkit";
 
 
 

🚨 다음과 같은 경고 발생

"reduxjs": Unknown word.cSpell

 

 

발생 원인

VS Code 확장자 중 'Code Spell Checker'에서 reduxjs를 오타로 인식

 

 

해결 방법

Quick fix → Add "reduxjs" to workspace settings → (자동) .vscode 폴더/settings.json 생성

1
2
3
4
5
6
{
    "cSpell.words": [
        "reduxjs"
    ]
}
 
 

 

 

 

참고 자료

 

vscode 확장 Code Spell Checker

Code Spell Checker 확장에 대해 간단하게 알아보겠습니다. Visual Studio Marketplace에서 확인할 수 있습니다. 이 글은 v2.1.6 버전을 기준으로 작성되었습니다. 세 줄 요약 코드에서 자동으로 영어 스펠링

lawner.tistory.com

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

발생 Error

React에서 다음 Source Code를 실행할 경우,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import redux from 'redux';
 
const counterReducer = (state = {counter: 0}, action) => {
    if(action.type === 'increment'){
        return {
            counter: state.counter + 1
        };
    }
    if(action.type === 'decrement'){
        return {
            counter: state.counter - 1
        };
    }
    return state;
};
 
const store = redux.createStore(counterReducer);
 
export default store;
 
 
 

🚨 다음과 같은 오류 발생

export 'default' (imported as 'redux') was not found in 'redux'

(possible exports: __DO_NOT_USE__ActionTypes, applyMiddleware, bindActionCreators, combineReducers, compose, createStore, legacy_createStore)

 

 

발생 원인

Redux 패키지는 기본적으로 객체 형태로 내보내기를 하고 있으며, default로 내보내는 항목이 없음
import redux from 'redux'와 같이 Redux 패키지를 가져오려고 할 경우 오류 발생

 

 

해결 방법

Redux 패키지에서 명시적으로 내보낸 함수나 객체를 선택적으로 가져올 수 있으므로 중괄호 {}를 사용하여 가져오고자 하는 항목을 지정

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import {createStore} from 'redux';
 
const counterReducer = (state = {counter: 0}, action) => {
    if(action.type === 'increment'){
        return {
            counter: state.counter + 1
        };
    }
    if(action.type === 'decrement'){
        return {
            counter: state.counter - 1
        };
    }
    return state;
};
 
const store = createStore(counterReducer);
 
export default store;
 
 
 

 

⚛️ 기본 환경: IDE: VS code, Language: React

 

 

발생 Error

React에서 다음 Source Code를 실행할 경우,

1
2
3
4
5
6
7
8
9
10
11
  const submitHandler = (event=> {
    event.preventDefault();
    if(formIsValid){
      authCtx.onLogin(emailState.value, pwdState.value);
    } else if(!emailIsValid) {
      emailInputRef.current.activate();
    } else {
      pwdInputRef.current.activate();
    }
  };
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const Login = (props) => {
  const emailInputRef = useRef();
 
  const submitHandler = (event=> {
    event.preventDefault();
    if(formIsValid){
      authCtx.onLogin(emailState.value, pwdState.value);
    } else if(!emailIsValid) {
      emailInputRef.current.activate();
    } else {
      pwdInputRef.current.activate();
    }
  };
 
  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <Input
          ref={emailInputRef}
          id="email"
          label="E-Mail"
          type="email"
          isValid={emailIsValid}
          value={emailState.value}
          onChange={emailChangeHandler}
          onBlur={validateEmailHandler}
        />
 
        <div className={classes.actions}>
          <Button type="submit" className={classes.btn}>
            Login
          </Button>
        </div>
      </form>
    </Card>
  );
};
 
 
 

🚨 다음과 같은 경고 발생

Warning: Function components cannot be given refs.

Attempts to access this ref will fail.

Did you mean to use React.forwardRef()?

 

 

발생 원인

함수 컴포넌트는 ref를 받을 수 없음, 즉 props 객체는 ref prop을 받아들이지 않음

 

 

해결 방법

useImperativeHandler Hook + forwardRef 사용

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
const Input = React.forwardRef((props, ref) => {
    const inputRef = useRef();
 
    const activate = () => {
        inputRef.current.focus();
    };
 
    useImperativeHandle(ref, () => {
        return ({
            focus: activate
        });
    });
 
    return (
    <div
      className={`${classes.control} ${
        props.isValid === false ? classes.invalid : ""
      }`}
    >
      <label htmlFor={props.id}>{props.label}</label>
      <input
        ref={inputRef}
        type={props.type}
        id={props.id}
        value={props.value}
        onChange={props.onChange}
        onBlur={props.onBlur}
      />
    </div>
  );
 
})
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
const Login = (props) => {
  const emailInputRef = useRef();
 
  const submitHandler = (event=> {
    event.preventDefault();
    if(formIsValid){
      authCtx.onLogin(emailState.value, pwdState.value);
    } else if(!emailIsValid) {
      emailInputRef.current.focus();
    } else {
      pwdInputRef.current.focus();
    }
  };
 
  return (
    <Card className={classes.login}>
      <form onSubmit={submitHandler}>
        <Input
          ref={emailInputRef}
          id="email"
          label="E-Mail"
          type="email"
          isValid={emailIsValid}
          value={emailState.value}
          onChange={emailChangeHandler}
          onBlur={validateEmailHandler}
        />
 
        <div className={classes.actions}>
          <Button type="submit" className={classes.btn}>
            Login
          </Button>
        </div>
      </form>
    </Card>
  );
};
 
 
 

useImperativeHandler(프로퍼티를 부여할 ref, 객체(추가하고싶은 prop 정의)를 리턴하는 함수)

→ React.forwardRef*((props, ref), () => {}): ref 인자 추가하여 forwardRef 선언

객체 정의에 맞춰 작동시키고자하는 함수 호출

 

 * forwardRef: 상위 컴포넌트에서 전달받은 ref를 하위 컴포넌트로 전달하는 역할

 

 

 

참고 자료

 

[React] useImperativeHandle의 장점

React hook 중에 useImperativeHandle 이라는 훅이 있다. 이 훅은 forwardRef 를 사용해서 ref를 사용하는 부모 측에서 커스터마이징된 메서드를 사용할 수 있게 해준다. 예를 들어 아래처럼 정의하면, function

developer-alle.tistory.com

 

useImperativeHandle 떠먹여드립니다.

비교적 생소한 훅일 수 있는 useImperativeHandle에 대해 알아보아요

velog.io