React

[React] useState

개발조각 2023. 9. 11. 22:11
728x90
반응형

리액트 훅 중에 기본 중에 기본인 useState에 대해 알아보자.

 

React에서 State란?


컴포넌트가 가질 수 있는 상태를 의미한다.

 

만약 시계라는 컴포넌트가 있으면 State는 time을 가질 수 있다.

useState는 컴포넌트의 상태를 가져오고 생성하고 업데이트를 해줄 수 있는 도구를 제공해 준다. 

 

useState의 기본형태

const [state, setState] = useState(초기값);
  • state : 현재의 상태값
  • setState : state를 변경시켜주고 싶을 때 사용

 

useState활용

const [time, setTime] = useState(5);
  • 초기값으로 5를 가지게 되고 이때는 time = 5이다.
  • 시간을 변경하려면 setTime(6)으로 넣어주면 time이 6이 된다.
    (인자에다가 변경하고 싶은 값을 넣어주면 된다.)

setState함수를 사용해서 state를 변경(업데이트)해주면 해당 컴포넌트는 렌더링이 된다.

time state가 변경될 때마다 화면이 업데이트가 된다.

 

예제 1 (시계)


import { useState } from "react";

function App() {
    return (
        <>
            <UseState />
        </>
    );
}

const UseState = () => {
    const [time, setTime] = useState(1);

    const handleClick = () => {
        setTime(time + 1);
    };
    return (
        <div>
            <span>현재 시각: {time}시</span>

            {/* 클릭할때마다 1씩 증가 */}
            <button onClick={handleClick}>Update</button>
        </div>
    );
};

export default App;

업데이트를 클릭할 때마다 화면이 렌더링이 된다. 

 

진짜로 업데이트를 클릭할때마다 화면이 렌더링이 되는지 확인하기 위해 콘솔 추가!

import { useState } from "react";

function App() {
    return (
        <>
            <UseState />
        </>
    );
}

const UseState = () => {
    const [time, setTime] = useState(1);

    const handleClick = () => {
        setTime(time + 1);
    };

    console.log("업데이트!!");
    return (
        <div>
            <span>현재 시각: {time}시</span>

            {/* 클릭할때마다 1씩 증가 */}
            <button onClick={handleClick}>Update</button>
        </div>
    );
};

export default App;

 

진짜 시계로 만들기 (현재 시각이 12시일 때 업데이트를 클릭하면 1로 되돌아감)

import { useState } from "react";

function App() {
    return (
        <>
            <UseState />
        </>
    );
}

const UseState = () => {
    const [time, setTime] = useState(1);

    const handleClick = () => {
        let newTime;
        if (time >= 12) {
            newTime = 1;
        } else {
            newTime = time + 1;
        }

        setTime(newTime);
    };

    console.log("업데이트!!");
    return (
        <div>
            <span>현재 시각: {time}시</span>

            {/* 클릭할때마다 1씩 증가 */}
            <button onClick={handleClick}>Update</button>
        </div>
    );
};

export default App;

 

예제 2  (입력 리스트)


import { useState } from "react";

function App() {
    return (
        <>
            <UseState2 />
        </>
    );
}

const UseState2 = () => {
    const [names, setNames] = useState(["홍길동", "김민수"]);
    const [input, setInput] = useState(""); // 현재 input안에 무슨 값을 가지고 있는지 트래킹 해주는 state

    const handleInputChange = ({ target }) => {
        setInput(target.value);
    };
    console.log(input);

    return (
        <div>
            <input type="text" onChange={handleInputChange} />
            <button>Update</button>

            {names.map((name, key) => (
                <p key={key}>{name}</p>
            ))}
        </div>
    );
};

export default App;

사용자가 input을 입력할 때마다 입력값이 나옴

이제 input에 이영희를 입력한 뒤 업로드버튼을 클릭하면 names에 저장이 되게 만들어 보자

 

입력값을 names에 저장되게 만들 때 아래와 같이 작성하면 안 된다.

setNames(["홍길동", "김민수", "이영희"]); // 이렇게 하면 안된다.

 

 

업데이트될 값은 이전값 + 입력값이다.

이전에 존재하는 state와 밀접한 관계가 있음으로 인자에다가 콜백함수를 전달해 주어야 된다.

콜백의 인자로는 업데이트해주기 전 이전상태의 state를 가지고 있다.

// 올바른 작성법
setNames((prevState) => [input, ...prevState]);

 

전체 코드

import { useState } from "react";

function App() {
    return (
        <>
            <UseState2 />
        </>
    );
}

const UseState2 = () => {
    const [names, setNames] = useState(["홍길동", "김민수"]);
    const [input, setInput] = useState(""); // 현재 input안에 무슨 값을 가지고 있는지 트래킹 해주는 state

    const handleInputChange = ({ target }) => {
        setInput(target.value);
    };
    const handleUpload = () => {
        // setNames(["홍길동", "김민수", "이영희"]); // 이렇게 하면 안된다.

        // 새로 업데이트 되는 값은 이전값 + 입력값 이다.
        // 콜백함수를 전달해주어야 된다.
        setNames((prevState) => [input, ...prevState]);
    };
    console.log(input);

    return (
        <div>
            <input type="text" onChange={handleInputChange} />
            <button onClick={handleUpload}>Update</button>

            {names.map((name, key) => (
                <p key={key}>{name}</p>
            ))}
        </div>
    );
};

export default App;

 

preveState에 이전 state값이 들어가 있는지 확인해 보자면

const handleUpload = () => {
    setNames((prevState) => {
        console.log("이전값: ", prevState);
        return [input, ...prevState];
    });
};

 

(잊지 말자!!) useState는 state가 업데이트될 때마다 화면이 렌더링이 된다.

만약 useState초기값을 가져올 때 무거운 작업을 해야 될 경우 (엄청 오래 걸리는 계산)

const [state, setState] = useState(무거운 작업 하는 중...)

컴포넌트가  계속해서 렌더링이 되기 때문에 무거운 작업을 하는 함수가 계속 다시 호출되는 현상이 반복된다.

이렇게 될 경우 성능에 굉장히 안 좋아진다.

리프레쉬하는 순간부터 엄청 무거운 작업이 실행되고,

state를 업데이트해줄 때마다 엄청 무거운 작업이 계속 실행되고 있다.

(엄청 비효율적이다.)

 

heavyWork함수가 맨 처음 렌더링 될 때만 불려지게 하고 싶다.

초기값을 넣어줄 인자에 콜백을 넣어주면 된다.

import { useState } from "react";

function App() {
    return (
        <>
            <UseState2 />
        </>
    );
}

const UseState2 = () => {
    const heavyWork = () => {
        console.log("엄청 무거운 작업!!!");
        return ["홍길동", "김민수"];
    };
    const [names, setNames] = useState(() => heavyWork());
    const [input, setInput] = useState("");

    const handleInputChange = ({ target }) => {
        setInput(target.value);
    };
    const handleUpload = () => {
        setNames((prevState) => {
            console.log("이전값: ", prevState);
            return [input, ...prevState];
        });
    };

    return (
        <div>
            <input type="text" onChange={handleInputChange} />
            <button onClick={handleUpload}>Update</button>

            {names.map((name, key) => (
                <p key={key}>{name}</p>
            ))}
        </div>
    );
};

export default App;

초기값을 가져올 때 무거운 작업을 해야 된다면 값을 넣어주는 게 아니라 콜백함수를 넣어줘야 된다.

그러면 화면이 처음 렌더링 될 때만 함수(무거운 작업)를 가져오게 된다.

 

정리


1. 

const [state, setState] = useState(초기값);

useState는 state, setState를 배열형태로 리턴해 준다.

state는 현재 상태값이 들어있고, setState는 state를 변경해 준다.

setState를 사용해서 state를 변경해 줄 때마다 화면이 렌더링이 된다.

 

2. 

setState((prevState)=>{
	// some works...
    return newState;
});

새로 변경될 state값이 이전 State값과 연관되어 있으면

setState 인자로 새로운 state리턴하는 콜백함수를 넣어주는 것이 좋다.

 

3. 

useState(()=>{
	return heavyWorks();
});

useState를 사용해서 초기값을 받아올 때 어떤 무거운 일을 해야 된다면

useState에 인자로 콜백함수를 넣어준다면 맨 처음 렌더링 될 때만 실행되게 할 수 있다.

 

 이 글은 별코딩 리액트 훅 강의를 보고 정리한 글입니다.

728x90
반응형