리액트

리액트 면접시 간단한(?)문제(useState, useEffect)

올바른생활부터 2024. 2. 26. 17:07
728x90
반응형
SMALL

리액트 기초부터 공부하는 와중에 친구의 추천으로 리액트 기본기 질문 영상을 보았는데 "예상 결괏값"을 맞춘게 하나도 없어서 필자는 react의 기본기에 대해 부족한 것 같아 영상에 말한 것을 정리해보았다.  
  이 글을 보고 있는 당신도 영상을 한번 보는 것을 권장한다.

 

 

1번

  • 결과 값은 어떻게 되는지?
function App() {
  console.log("init");
  const [state, setState] = useState(0);
  console.log("state:", state);

  useEffect(() => {
    console.log("effect");
    setState(1);
  }, []);

  return <div className="App"></div>;
}

 

[정답]

function App() {
  console.log("init");
  const [state, setState] = useState(0);
  console.log("state:", state);

  useEffect(() => {
    console.log("effect");
    setState(1);
  }, []);

  return <div className="App"></div>;
}

// 결과
// init
// state: 0
// effect
// init
// state: 1

 

2번

  • 결과 값은 어떻게 되는지?
function App() {
  const [state, setState] = useState(0);
  console.log("state:", state);

  useEffect(() => {
    setState(1);
  }, [state]);

  return <div className="App"></div>;
}

 

[정답]

function App() {
  const [state, setState] = useState(0);
  console.log("state:", state);

  useEffect(() => {
    setState(1);
  }, [state]);

  return <div className="App"></div>;
}

// 결과
// state: 0
// state: 1
// state: 1
  • dependency array에 state를 넣으면 3개의 결괏값이 나온다.
  • 함수형 컴포넌트에서 **useState**를 사용할 때, 상태(state)를 변경하는 함수인 **setState()**를 호출하면 컴포넌트가 다시 렌더링된다.

첫 번째 호출:

  • 컴포넌트가 처음 렌더링될 때, **useState(0)**으로 초기 상태를 설정한다.
  • state 값은 0이 되고, **console.log("state:", state);**가 실행되어 "state: 0"이 출력된다.

두 번째 호출:

  • **useEffect**는 컴포넌트가 렌더링될 때와 상태가 변경될 때마다 실행됩니다.
  • **useEffect**의 의존성 배열에 **[state]**를 지정했으므로, state 값이 변경될 때마다 **useEffect**가 실행됩니다.
  • **setState(1)**을 호출하여 상태를 1로 변경합니다.
  • **console.log("state:", state);**가 다시 실행되는데, 이때 state 값은 이미 1로 변경된 상태입니다. 따라서 "state: 1"이 다시 출력됩니다.

즉, setState(1)로 인해 state가 1이 되고, state상태값이 변경되면서 위에서 코드가 실행되어 state: 1 출력함. 그리고 dependency array의 state값을 지정했으므로, state값이 변경되면 setState(1)가 또 실행된다.

 

 

3번

  • 결과 값은 어떻게 되는지?
function App() {
  const [state, setState] = useState(0);
  console.log("state:", state);

  useEffect(() => {
    setState(1);
    return () => { // 클린업 함수
      console.log(state);
    };
  }, [state]);

  return <div className="App"></div>;
}

 

[정답]

function App() {
  const [state, setState] = useState(0);
  console.log("state:", state);

  useEffect(() => {
    setState(1);
    return () => { // 클린업 함수
      console.log(state);
    };
  }, [state]);

  return <div className="App"></div>;
}

// state: 0
// state: 1
// 0
// state: 1
  • 첫 번째 렌더링에서 **state**의 초기값은 0이므로, **useEffect**가 실행되면 **setState(1)**이 호출되어 state 값이 1로 변경되지만, 이 때 클린업 함수는 여전히 첫 번째 렌더링 때의 state 값인 0을 참조하게 되어 0을 출력한다.
  • 이는 JavaScript의 클로저 특성 때문이다. **useEffect**의 클린업 함수는 state 값이 변경되더라도 클린업 함수가 최초에 선언된 시점의 state 값을 계속 참조하게 됩니다.

 

4번

  • 결과 값은 어떻게 되는지?
function App() {
  const [state, setState] = useState(0);

  useEffect(() => {
    setState(1);
    console.log(state);
    setState(2);
    console.log(state);
    setState(3);
    console.log(state);
  }, [state]);

  return <div className="App"></div>;
}

 

[정답]

function App() {
  const [state, setState] = useState(0);

  useEffect(() => {
    setState(1); 
    console.log(state); // 0
    setState(2);
    console.log(state); // 0
    setState(3); // 최종적으로 3이 나옴
    console.log(state); // 0
  }, [state]);

  return <div className="App"></div>;
}

// 결괏값
// 0
// 0
// 0
// 3
// 3
// 3

실행순서

  1. useEffect 내부에서 console.log(state) 를 호출하면 setState 호출 이후에도 state 값이 업데이트되지 않기 때문에 항상 초기값인 0이 출력된다.
  2. 그리고 useEffect의 두 번째 인자로 state를 전달하기 때문에 state 값이 변경될 때마다 useEffect내부의 코드가 실행된다.
  3. 마지막에 있는 setState(3)을 호출하면 state 값이 3으로 변경되고, 이로 인해 useEffect가 다시 실행되어 console.log(state)가 3을 출력하여 총 3이 반복되어 출력된다.

 

5번

function App() {
  const [state, setState] = useState(0);
  console.log(state);

  useEffect(() => {
    setState(state + 1);
    setState(state + 1);
    setState(state + 1);
  }, []);

  return <div className="App"></div>;
}

 

[정답]

function App() {
  const [state, setState] = useState(0);
  console.log(state);

  useEffect(() => {
    setState(state + 1); // 0+1
    setState(state + 1); // 0+1
    setState(state + 1); // 0+1
  }, []);

  return <div className="App"></div>;
}

// 결괏값
// 0
// 1
  • useEffect의 두 번째 인자로 빈 배열([])을 전달했기 때문에 useEffect 내부의 코드는 컴포넌트가 처음 렌더링될 때 단 한 번만 실행된다. 그래서 state 값은 1로 변경된 후 더 이상 변경되지 않아 1이 출력된다.
function App() {
  const [state, setState] = useState(0);
  console.log(state);

  useEffect(() => {
    setState(1); // 1
  }, []);

  return <div className="App"></div>;
}

// 결괏값
// 0
// 1
  • 엄밀히 말하면 이런식으로 표현된다.

 

6번

  • 이전 state가 반영되는 문제
function App() {
  const [state, setState] = useState(0);
  console.log(state);

  useEffect(() => {
    setState((prev) => prev + 1);
    setState((prev) => prev + 1);
    setState((prev) => prev + 1);
  }, []);

  return <div className="App"></div>;
}

[정답]

function App() {
  const [state, setState] = useState(0);
  console.log(state);

  useEffect(() => {
    setState((prev) => prev + 1);
    setState((prev) => prev + 1);
    setState((prev) => prev + 1);
  }, []);

  return <div className="App"></div>;
}

// 결괏값
// 0
// 3
  • useEffect 내부에서 **setState((prev) => prev + 1)**을 세 번 호출하고 있다. 이 때 setState 함수에 함수를 인자로 전달하면, React는 이전 state 값을 인자로 해당 함수를 호출하여 새 state 값을 계산한다.
  • 따라서 세 번의 setState 호출로 인해 state 값은 **0 + 1 + 1 + 1 = 3**으로 변경된다.

7번

function App() {
  const [state, setState] = useState(0);
  const [value, setValue] = useState(0);
  console.log(value);

  useEffect(() => {
    setState(3);
    setValue(state);
  }, []);

  return <div className="App"></div>;
}

 

[정답]

function App() {
  const [state, setState] = useState(0);
  const [value, setValue] = useState(0);
  console.log(value);

  useEffect(() => {
    setState(3);
    setValue(state);
  }, []);

  return <div className="App"></div>;
}

// 결괏값
// 0
// 0
  • 이 코드에서는 useEffect 내부에서 **setState(3)**을 호출한 후에 **setValue(state)**를 호출하고 있다. 이 때 state 값은 **useEffect**가 호출될 때의 값, 즉 **0**을 가지고 있다. 따라서 **setValue(state)**는 **setValue(0)**이 되어 value 값은 **0**으로 설정된다.
  • useEffect의 두 번째 인자로 빈 배열([])을 전달했기 때문에 useEffect 내부의 코드는 컴포넌트가 처음 렌더링될 때 단 한 번만 실행됩니다. 따라서 value 값은 **0**으로 변경된 후 더 이상 변경되지 않는다.

8번

  • 밑 코드의 결과값처럼 콘솔에 두번 출력되는 이유는?
import { useEffect, useState } from "react";

function App() {
  useEffect(() => {
    console.log("effect");
  }, []);

  return <div className="App"></div>;
}

export default App;

// 결괏값
// effect
// effect

 

 

[정답]

const root = ReactDOM.createRoot(document.getElementById("root"));

root.render(
  <StrictMode>
    <App />
  </StrictMode>
);
  • <StrictMode>의 여부에 따라 useEffect 안에서 코드이 호출 횟수가 달라진다.

※ 출력되는 이유는 검증용으로 실행되는 것이다.

참고

728x90
반응형
LIST