일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 포이마웹
- 백준구현문제
- 백준알고리즘
- 프로그래머스
- 백준nodejs
- css기초
- JS프로그래머스
- CSS
- 알고리즘
- 익스프레스
- 리액트커뮤니티
- 코딩테스트
- dp알고리즘
- HTML
- 다이나믹프로그래밍
- 백준js
- HTML5
- 리액트댓글기능
- 리액트
- 자바스크립트
- 안드로이드 스튜디오
- 백준구현
- 백준골드
- 코테
- 백준
- 프로그래머스코테
- JS
- js코테
- 프로그래머스JS
- 몽고DB
- Today
- Total
개발새발 로그
React - useState에 대하여 본문
useState
상태
컴포넌트의 상태를 간단하게 생성하고 업데이트 할 수 있게 해준다.
const [state, setState] = useState(initialState);
setState를 사용해서 state을 변경하면 다시 렌더링하게 된다.
그래서 컴포넌트 안의 함수와 변수가 다시 호출된다.
1. 초기값을 저장할 때 주의할 점!
그럼 만약 useState로 만든 state값의 초기 값에 무거운 작업을 해서 값을 저장하게 된다면
컴포넌트가 계속해서 렌더링될 때 성능에 굉장히 안좋을 수 있다.
아래 예를 보자
const heavyWokr =()=>{
console.log("엄청 무거운 작업!!!")
retrun ['홍길동','김민수']
}
const App=()=>{
const [names,setNames] = useState(heavyWork());
const [input,setInput] =useState('');
const handleInputChange = (e) =>{
setInput(e.target.value);
}
const handleUpload = () =>{
setNames((prev)=>{
return [input,...prev]
});
}
return (
<div>
<input type='text' onChange={handleInputChange}/>
<button onClick={handleUpload}>Upload</button>
{names.map((name,idx)=>{
return <p key={idx}>name<p>
})}
</div>
)
}
그저 input 요소에 값을 입력해서 names 에 해당 값을 저장하고 출력해주는 로직이다.
근데 여기서 만약 input 요소에 값을 입력하는 행동을 한다면 아래와 같이 콘솔에 타이핑 수만큼 함수가 출력될 것이다.
이는
input요소에 타이핑을 할 때
컴포넌트가 첫 렌더링을 할 때
Upload버튼을 클릭했을 때
모두 heavyWorK함수가 실행 된다.
정말 비효율적이다.
이를 해결하기 위해서는 heavyWork함수를 처음에 렌더링이 될 때만 불려지게 하는 것이다.
아래와 같이 콜백함수로 넣어주게 되면 맨 처음화면을 렌더링할 때만 불려지게 된다.
const [names,setNames] = useState(()=>{
return heavyWork();
});
아래와 같이 초기화 함수로 전달할 수 있다.
// 이렇게 하면 안돼요!
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos());
// ...
}
// 초기화 함수를 사용하세요
function TodoList() {
const [todos, setTodos] = useState(createInitialTodos);
// ...
}
함수를 호출한 결과인 createInitialTodos()가 아니라 함수 자체인 createInitialTodos를 전달하고 있다는 것을 봐야한다.
함수를 useState에 전달하면 React는 초기화 중에만 함수를 호출한다.
React는 이니셜라이저가 순수한지 확인하기 위해 개발 과정에서 이니셜라이저를 두 번 호출할 수도 있다.
2. setState시 주의할 점!
set 함수를 호출해도 이미 실행 중인 코드의 현재 상태는변경되지 않습니다
function handleClick() {
setName('Robin');
console.log(name); // 여전히 "테일러"!
}
다음 렌더링부터 반환되는 useState에만 영향을 줍니다.
3. setState는 이전상태를 기준으로 업데이트한다!
나이가 42세라고 가정합니다. 이 핸들러는 setAge(age + 1 )를 세 번 호출합니다
function handleClick() {
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
setAge(age + 1); // setAge(42 + 1)
}
하지만 한 번만 클릭하면 나이는 45세가 아니라 43세가 됩니다! 이는 set 함수를 호출해도 이미 실행 중인 코드에서 나이 상태 변수가 업데이트되지 않기 때문입니다. 따라서 각 setAge(age + 1) 호출은 setAge(43)이 됩니다.
이 문제를 해결하려면 다음 상태 대신 setAge에 업데이터 함수를 전달할 수 있습니다:
function handleClick() {
setAge(a => a + 1); // setAge(42 => 43)
setAge(a => a + 1); // setAge(43 => 44)
setAge(a => a + 1); // setAge(44 => 45)
}
여기서 a => a + 1은 업데이터 함수입니다. 이 함수는 보류 중인 상태를 가져와서 다음 상태를 계산합니다.
React는 업데이터 함수를 대기열에 넣습니다. 그런 다음 다음 렌더링 중에 동일한 순서로 호출합니다:
- a => a + 1은 보류 중인 상태로 42를 수신하고 다음 상태로 43을 반환합니다.
- a => a + 1은 보류 중인 상태로 43을 수신하고 다음 상태로 44를 반환합니다.
- a => a + 1은 보류 중인 상태로 44를 수신하고 다음 상태로 45를 반환합니다.
대기 중인 다른 업데이트가 없으므로 React는 결국 45를 현재 상태로 저장합니다.
일반적으로 상태 변수 이름의 첫 글자를 보류 중인 상태 인수의 이름으로 지정하는 것이 일반적입니다(예: for age) . 하지만 더 명확하다고 생각되는 다른 이름을 prevAge 등으로 지을 수도 있습니다.
React는 개발 과정에서 업데이트가 순수한지 확인하기 위해 업데이트자를 두 번 호출할 수 있습니다.
-> 컴포넌트 순수성 유지
리액트의 "순수성"은 컴포넌트가 주어진 입력에 대해 동일한 출력을 생성하는 것을 의미한다.
즉, 동일한 프로퍼티와 상태에 대해 항상 동일한 결과를 렌더링하는 것입니다.
4. state는 객체도 될 수 있다!
상태의 개체 및 배열 업데이트
객체와 배열을 state에 넣을 수 있습니다.
React에서 state는 읽기 전용으로 간주되므로 기존 객체를 변경하지 말고 대체해야 합니다.
// 🚩 이런 상태의 개체는 변경하지 마세요:
form.firstName = 'Taylor';
대신 새 개체를 생성하여 전체 개체를 교체한다.
// ✅ state를 새 객체로 바꾸기
setForm({
...양식,
이름: 'Taylor'
});
아래와 같이 사용한다.
const [form, setForm] = useState({
firstName: 'Barbara',
lastName: 'Hepworth',
email: 'bhepworth@sculpture.com',
});
...
<input
value={form.lastName}
onChange={e => {
setForm({
...form,
lastName: e.target.value
});
}}
/>
...
5. key로 상태 재설정하기
map을 사용할 때 key 속성을 자주 접하게 된다.
하지만 key속성을 이용해서 다른 기능이 사용가능하다.
다른 컴포넌트에 key값을 전달하고,
해당 key값을 변경하면
React는 해당 컴포넌트를 처음부터 다시 생성하므로 상태가 초기화된다.
import { useState } from 'react';
export default function App() {
const [version, setVersion] = useState(0);
function handleReset() {
setVersion(version + 1);
}
return (
<>
<button onClick={handleReset}>Reset</button>
<Form key={version} />
</>
);
}
function Form() {
const [name, setName] = useState('Taylor');
return (
<>
<input
value={name}
onChange={e => setName(e.target.value)}
/>
<p>Hello, {name}.</p>
</>
);
}
위 코드는 reset버튼이 있고,
Form 컴포넌트에서는 데이터 입력과 출력을 하고 있다.
이때 input의 값은 Taylor로 초기화되어있어 처음 렌더링 했을 때 Taylor을 나타나게 된다.
input의 값을 타이핑해서 변경하다가 reset버튼을 누르면
다시 Taylor로 값이 바뀌게 된다.
이는 Form에 넘겨지는 key값이 변경되었고,
React에서는 해당 컴포넌트를 처음부터 다시 생성한다.
그래서 Taylor로 초기화 된 것이다!
'React' 카테고리의 다른 글
React - useContext에 대하여 (1) | 2023.12.11 |
---|---|
React - useRef에 대하여 (0) | 2023.12.11 |
React - useEffect에 대하여 (0) | 2023.12.11 |
React - 분기와 반복( 논리곱연산자,삼항연산자, map) (1) | 2023.12.05 |
[리액트] Vite Eslint 설정하기 - 리액트 Eslint 오류가 안뜸 (0) | 2023.09.24 |