가장 기본적인 hook
함수형 컴포넌트 내에서 가변적인 상태를 갖게 함
카운터, Todolist
const[state,setState] = useState(초기값)
함수형 업데이트
import React, { useState } from "react";
import "./App.css";
function App() {
const [number, setNumber] = useState(0);
return (
<>
<div>Number State {number}</div>
<button
onClick={() => {
// setNumber(number + 1);
// setNumber(number + 1);
// setNumber(number + 1);
// 세 개 넣어도 1 올라감
//배치성으로 처리되어 배치 업데이트가 되기 때문이다
//(한꺼번에 변경된 걸 모아서 한 번만 반영)
// 렌더링이 잦다 -> 성능 이슈가 있는 것
setNumber((currentNumber) => currentNumber + 1);
setNumber((currentNumber) => currentNumber + 1);
setNumber((currentNumber) => currentNumber + 1);
// //함수형 업데이트
// 세 개 넣으면 3 올라감
// 명령을 모아서 순차적으로 한 번씩 실행시킴
// 인자 부분에 현재의 state가 들어오고
//안에서는바뀐 state를 반환하니까 각각 최신값들을 유지할 수 있어서
// 0에서 1올라가고 1에서 2 올라가고 2에서 3 올라갈 수 있는 것,,
}}
>
누르면 Up
</button>
</>
);
}
export default App;
의존성 배열(dependency array) : 이 배열에 값을 넣으면, 그 값이 바뀔 때만 useEffect 를 실행한다.
렌더링 될 때마다 특정한 작업을 수행해야 할 때 설정하는 훅
컴포넌트가 화면에 보여졌을 때
컴포넌트가 화면에서 사라졌을 때(return)
import React, { useEffect, useState } from "react";
function App() {
const [value, setValue] = useState("");
useEffect(() => {
console.log(`hello, useEffect : ${value}`);
return () => {
console.log("나 사라져요");
// 컴포넌트 죽을 때 로직이 동작함
};
}, [value]);
return (
<div>
<input
type="text"
value={value}
onChange={(event) => {
setValue(event.target.value);
}}
//1.input에 값을 입력
// 2. value, 즉 state가 변경
//3. state가 바뀌었기 때문에 -> App 컴포넌트가 리렌더링
//4. 리렌더링 -> useEffect
//5. 1-4번 반복
//Dependency Array 필요
></input>
</div>
);
}
export default App;
Dom요소 접근 방법으로서의 useRef
렌더링 되자마자 특정 input태그가 focusing이 돼야하는 경우 등 Dom을 선택해야 할 상황이 생길 때 사용한다.
import React, { useRef } from "react";
function App() {
const ref = useRef("초기값");
//ref :reference(참조)
console.log("ref", ref);
ref.current = "변경값";
console.log("ref2", ref);
return <div>App</div>;
}
export default App;
이렇게 설정된 ref값은 컴포넌트가 계속해서 렌더링되어도 unmount 전까지 값을 유지한다!
저장공간으로서의 useRef
State 와 Ref의 차이
import React, { useRef, useState } from "react";
const style = {
border: "1px solid black",
margin: "10px",
padding: "10px",
};
function App() {
const [count, setCount] = useState(0);
const countRef = useRef(0);
const plusStateCountButtonHandler = () => {
setCount(count + 1);
};
const plusRefCountButtonHandler = () => {
countRef.current++;
};
return (
<>
<div style={style}>
state 영역입니다. {count} <br />
<button onClick={plusStateCountButtonHandler}>state 증가</button>
</div>
<div style={style}>
ref 영역입니다. {countRef.current}
<br />
<button onClick={plusRefCountButtonHandler}>ref 증가</button>
</div>
</>
);
}
export default App;
Dom요소 접근 방법으로서의 useRef 예시
import React, { useEffect, useRef, useState } from "react";
function App() {
//화면이 렌더링될 때 어떤 작업을 하고싶다! : useEffect
const idRef = useRef("");
const passwordRef = useRef();
const [id, setId] = useState("");
useEffect(() => {
idRef.current.focus();
}, []);
useEffect(() => {
if (id.length >= 10) {
passwordRef.current.focus();
}
}, [id]);
//id라는 state가 바뀔때마다 수행이 되야하기때문에 id가 들어가야함
return (
<>
<div>
아이디 :{" "}
<input
value={id}
onChange={(event) => {
setId(event.target.value);
}}
type="text"
ref={idRef}
></input>
</div>
<div>
패스워드 : <input type="password" ref={passwordRef}></input>
</div>
</>
);
}
export default App;
react context의필요성
일반적으로 부모컴포넌트에서 자식 컴포넌트로 데이터를 전달해줄 때 props를 사용했다.
하지만 너무 깊어지게 되면 prop drilling이 일어난다.
prop drilling의 문제점
이러한 문제를 해결하기 위해 react context API가 필요하고 useContext hook을 통해 쉽게 전역데이터를 관리할 수 있다.
context API 필수개념
주의해야 할 사항
렌더링 문제
uesContext를 사용할 때, Provider에서 제공한 value가 달라진다면 useContext를 사용하고 있는 모든 컴포넌트가 렌더링된다. 따라서 value 부분을 항상 신경써줘야 한다. → 대안 : 메모이제이션
사용 예)
components/GrandFather.jsx
import React from "react";
import Father from "./Father";
import { FamilyContext } from "../context/FamilyContext";
//GF -> Child한테 어떤 정보를 알려줘서 Child가 그 내용을 출력하도록//?!
function GrandFather() {
const houseName = "sparta";
const pocketMoney = 10000;
return (
<FamilyContext.Provider
value={{
houseName,
pocketMoney,
}}
>
<Father />
</FamilyContext.Provider>
);
}
export default GrandFather;
Father.jsx
import React from "react";
import Child from "./Child";
function Father() {
return <Child />;
}
export default Father;
Child.jsx
import React, { useContext } from "react";
import { FamilyContext } from "../context/FamilyContext";
const style = {
color: "red",
fontWeight: "900",
};
function Child() {
const data = useContext(FamilyContext);
console.log(data);
return (
<div>
나는 이 집안의 막내예요. <br />
할아버지가 우리집 이름은 <span style={style}>{data.houseName}</span>이라고
하셨어요. <br />
게다가 용돈도 <span style={style}>{data.pocketMoney}</span>원 만큼이나
주셨어요!
</div>
);
}
export default Child;
App.jsx
import React from "react";
import GrandFather from "./components/GrandFather";
function App() {
return <GrandFather/>
}
export default App;
context/FamilyContext.js
import { createContext } from "react";
export const FamilyContext = createContext(null);