State는 컴포넌트에 대한 데이터 또는 정보를 포함하는 데 쓰이는 React 객체이다.
컴포넌트 상태는 변경될 때마다 컴포넌트가 다시 렌더링되며, 사용자의 작업이나 이벤트에 대한 응답으로 발생할 수 있다.
상태의 변경은 컴포넌트의 동작, 렌더링 방법을 결정한다.
State를 사용하는 방법은 useState을 사용하는 것이다. (함수형 컴포넌트를 기준으로 학습한다.)
useState는 리액트의 기본 Hook중 하나로, 컴포넌트에서 state를 동적으로 추가하고 변경할 때 사용한다.
const {useState} from 'react';
const [state, setState] = useState('state');
기본 형태는 위와 같으며 useState의 ()안의 값은 초기 state값을 넣을 수 있으며 초기 값은 어떤 데이터 타입이든 가능하다.
리턴값은 첫번째로는 상태값인 state, 두번째로는 state를 변경하는 함수이다.
const state = useState('initialState');
console.log(state);
위 코드를 실행해보면 아래의 결과를 통해 첫번째 인덱스로 초기값인 'initialState' 두번째 인덱스로 state를 변경하는 함수가 리턴되는것을 확인할 수 있다.

프로젝트에 useState를 사용해 추가된 todo를 부모컴포넌트인 App 컴포넌트로 전달하여 출력해보자.
import {useState} from 'react';
const ToDoForm = (props) => {
const [todo, setTodo] = useState('');
const changeHandler = (event) => {
setTodo(event.target.value);
}
const submitHandler = (event) => {
event.preventDefault();
const todoList = {title: todo, id: Math.random()};
props.onGetTodo(todoList);
setTodo('');
}
return (
<div>
<form onSubmit={submitHandler}>
<label htmlFor='todoInput'>Type your To Do.</label>
<input onChange={changeHandler} value={todo} id='todoInput' type='text'></input>
<button type='submit'>Add</button>
</form>
</div>
);
};
export default ToDoForm;
우선, input태그에 onChange 이벤트를 추가해 changeHandler함수를 선언한다.
input의 값이 변경될때마다 changeHandler 함수 내부의 setTodo state변경 함수가 실행되며 변경되는 state는 input의 value값이다.
form이 제출되면 props로 부모 컴포넌트로부터 받은 onGetTodo함수가 실행되며 새로운 state가 title로 들어간 객체가 부모 컴포넌트로 전달된다.
import { useState } from 'react';
import './App.css';
import ToDoForm from './components/ToDoForm/ToDoForm';
import ToDoList from './components/ToDoList/ToDoList';
function App() {
const [todoList, setTodoList] = useState([]);
const getToDo = (todo) => {
setTodoList((prevList) => {
return [...prevList, todo];
});
};
const deleteToDo = (id) => {
setTodoList((prevList) => {
const updatedList = prevList.filter(list => list.id !== id);
return updatedList;
});
}
return (
<div className="App">
<ToDoForm onGetTodo={getToDo}></ToDoForm>
<ToDoList todoList={todoList} onDeleteTodo={deleteToDo}></ToDoList>
</div>
);
}
export default App;
부모 컴포넌트인 App에서도 하드코딩된 배열을 삭제하고 새로운 todoList배열 state를 useState를 사용해 관리한다.
자식 컴포넌트인 ToDoForm에서 getToDo함수를 호출해 새로운 객체를 넘겼기 때문에 setTodoList함수가 실행된다.
state를 변경하는데 있어서 이전의 state값을 참조하기 위해서는 위와 같이 state 변경 함수인 setTodoList에 함수를 전달해 파라미터로 전달된 값을 통해 접근할 수 있다.
위에서 설명했듯이 state가 변경될때 컴포넌트가 다시 실행되기 때문에 ToDoList 컴포넌트에 props로 전달한 todoList는 최신상태의 todoList가 전달이 된다.
그리고 완료된 todo 삭제를 위해 deleteToDo 함수를 선언해 ToDoList 컴포넌트에게 props로 전달하고 실행시 해당 todo의 id를 파라미터로 받고 현재 todoList 상태에 filter함수를 이용해 일치하지 않는 todo만 리턴한다.
앞서 말했듯이 state를 변경하는 함수가 실행될경우 컴포넌트가 재평가 되기때문에 사용자에게는 삭제된것 처럼 보이게 된다.
const ToDoList = (props) => {
const clickHandler = (id) => {
props.onDeleteTodo(id);
}
return (
<div>
<ul>
{props.todoList.map((list) => {
return (
<li key={list.id}>
<span>{list.title}.</span>
<button onClick={() => {clickHandler(list.id)}} type="button">X</button>
</li>
);
})}
</ul>
</div>
);
};
export default ToDoList;
완료된 todo를 삭제하기 위해 부모 컴포넌트인 App에서 onDeleteTodo를 props로 받고 생성된 list의 id를 파라미터로 전달한다.
다음에는 컴포넌트에 css를 적용하는 방법에 대해서 알아보자.
이전의 state값을 참조하는 방법은 ➡️ 나중에 알아보자.