본문 바로가기
JavaScript/React with Error

[해결 방법] React Hook "useState" cannot be called inside a callback 2

by HJ0216 2023. 6. 3.

⚛️ 기본 환경: 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