🟨 기본 환경: IDE: VS code, Language: JavaScript

 

 

발생 Error

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const redux = require('redux');
 
const counterReducer = (state, action) => {
    return {
        counter: state.counter + 1
    };
};
 
const store = redux.createStore(counterReducer);
 
const counterSubscriber = () => {
    const latestState = store.getState();
    console.log(latestState);
};
 
store.subscribe(counterSubscriber); // 데이터 변경 시 실행
 
 
 

🚨 다음과 같은 Error 발생

counter: state.counter + 1
TypeError: Cannot read properties of undefined (reading 'counter')

 

 

발생 원인

createStore() → counterReducer 호출 → 새로운 state return

기존의 state가 정의되어있지 않아서 TypeError 발생

 

 

해결 방법

기존 state의 기본값 부여

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const redux = require('redux');
 
const counterReducer = (state = {counter: 0}, action) => {
    return {
        counter: state.counter + 1
    };
};
 
const store = redux.createStore(counterReducer);
 
const counterSubscriber = () => {
    const latestState = store.getState();
    console.log(latestState);
};
 
store.subscribe(counterSubscriber); // 데이터 변경 시 실행
 
 
 

 

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

 

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

 

 

발생 Error

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

1
2
3
4
5
6
7
8
9
10
  useEffect(() => {
    useState();
 
    console.log('EFFECT RUNNING');
 
    return () => {
      console.log('EFFECT CLEANUP');
    };
  }, []);
 
 
 

🚨 다음과 같은 오류 발생

React Hook "useState" cannot be called inside a callback.

React Hooks must be called in a React function component or a custom React Hook function

 

 

발생 원인

use로 시작하는 ReactHook을 ReactHook함수 안에서의 중첩 사용 또는 최상위가 아닌 수준에서 ReactHook 호출

 

 

해결 방법

ReactHook을 최상위 수준( =Component안에서 직접적 선언)에서 React 함수(returnType JSX) 또는 사용자 정의 함수 안에서만 직접적으로 호출

 

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

 

 

발생 Error

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

1
2
3
4
5
6
7
8
9
10
11
12
13
const emailReducer = (state, action) => {
  useState();
 
  if(action.type === 'USER_INPUT'){
    return {value : action.value, isValid: action.value.includes('@')};
  }
  if(action.type === 'INPUT_BLUR'){
    return {value : state.value, isValid: state.value.includes('@')};
  }
 
  return {value: '', isValid: false};
};
 
 
 

🚨 다음과 같은 오류 발생

React Hook "useState" is called in function "emailReducer" that is neither a React function component nor a custom React Hook function.

React component names must start with an uppercase letter. React Hook names must start with the word "use"

 

 

발생 원인

use로 시작하는 ReactHook을 React 함수(returnType JSX) 또는 사용자 정의 함수 밖에서 호출

 

 

해결 방법

ReactHook을 React 함수(returnType JSX) 또는 사용자 정의 함수 안에서 호출

 

이 글은 [[한글자막] React 완벽 가이드 with Redux, Next.js, TypeScript]를 수강하며 정리한 글입니다.

 

 

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

 

 

React.createContext()

: 컴포넌트에게 props를 사용하지 않고 필요한 데이터를 넘겨주며 사용할 수 있게 해 줌으로써 컴포넌트들이 데이터(state)를 더 쉽게 공유할 수 있도록 함

 

React.createContext() 사용법

1. React createContext() 선언

1
2
3
4
5
6
7
8
9
import React from 'react';
 
const AuthContext = React.createContext({
    isLoggedIn: false
});
// AuthContext: Component는 아니지만 Component를 포함하는 객체
 
export default AuthContext;
 
 
 

 

2. AuthContext가 필요한 Component 감싸기

1
2
3
4
5
6
7
8
9
10
  return (
    <AuthContext.Provider value={{isLoggedIn: isLoggedIn,}}>
      <MainHeader isAuthenticated={isLoggedIn} onLogout={logoutHandler} />
      <main>
        {!isLoggedIn && <Login onLogin={loginHandler} />}
        {isLoggedIn && <Home onLogout={logoutHandler} />}
      </main>
    </AuthContext.Provider>
  );
 
 
 

⭐ AuthContext 자체는 component가 아니므로 Provider를 같이 사용하여 Component화

→ <AuthContect.Provider> 안의 Component들은 모두 AuthContext의 데이터를 공유

 * Provider 역할: 값 설정 및 전달

 

3. AuthContext 사용 선언

 - <AuthContext.Consumer>

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
const Navigation = (props) => {
  return (
     <AuthContext.Consumer>
       {(ctx) => {
         return (
          <nav className={classes.nav}>
            <ul>
              {ctx.isLoggedIn && (
                <li>
                  <a href="/">Users</a>
                </li>
              )}
              {ctx.isLoggedIn && (
                <li>
                  <a href="/">Admin</a>
                </li>
              )}
              {ctx.isLoggedIn && (
                <li>
                  <button onClick={props.onLogout}>Logout</button>
                </li>
              )}
            </ul>
          </nav>
         );
       }}
     </AuthContext.Consumer>
  );
};
 
 
 

 - useContext()

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
const Navigation = (props) => {
  const ctx = useContext(AuthContext);
 
  return (
    <nav className={classes.nav}>
      <ul>
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Users</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <a href="/">Admin</a>
          </li>
        )}
        {ctx.isLoggedIn && (
          <li>
            <button onClick={props.onLogout}>Logout</button>
          </li>
        )}
      </ul>
    </nav>
  );
};
 
 
 

 

 

 

참고 자료

 

초보자를 위한 리액트 Context - 완벽 가이드 (2021)

리액트 context는 모든 리액트 개발자들이 필수적으로 알아야 하는 개념입니다. context는 앱에서 state를 쉽게 공유할 수 있게 해줍니다. 이 글에서는 리액트 context가 무엇인지, 어떻게 사용하는지,

www.freecodecamp.org