다시 랜더링 되어도 동일한 참조값을 유지하려면?
컴포넌트 내부 변수의 저장공간이 필요하다. 이 때 사용하는 것이 useRef Hook이다.
useRef로 선언한 변수는 값이 변하더라도 렌더링이 일어나지 않고, 렌더링이 일어나더라도 값을 유지할 수 있다
const 변수명 = useRef(초기값)
변수명.current
로 가져올 수 있다.변수명.current = ...
로 변경시킬 수 있다정리
state 변화 → 렌더링 → 컴포넌트 내부 변수들 초기화
ref변화 → No 렌더링 → 변수들의 값이 유지됨
state의 변화 → 렌더링 → ref의 값 유지됨
useRef() 작동 이해
import {useState, useRef, useEffect} from "react";
function App() {
const [countState, set_countState] = useState(0);
const countRef = useRef(0)
let countVar = 0
const totalRenderingCnt = useRef(0)
useEffect(() => {
totalRenderingCnt.current = totalRenderingCnt.current + 1;
console.log("렌더링 수 : ", totalRenderingCnt.current)
})
function increaseCountState() {
set_countState(countState + 1)
}
function increaseCountRef() {
countRef.current = countRef.current + 1
console.log("Ref : ",countRef);
}
function increaseCountVar() {
countVar = countVar + 1;
console.log("Var : ",countVar);
}
function pringResult() {
console.log("state ; ", countState "ref : ", countRef.current, "var : ", countVar )
}
return (
<div className="App">
<p>State : {countState}</p>
<p>Ref : {countRef.current}</p>
<p>Var : {countVar}</p>
<button onClick={increaseCountState}>State 증가</button>
<button onClick={increaseCountRef}>Ref 증가</button>
<button onClick={increaseCountVar}>Var 증가</button>
<button onClick={pringResult}>state, ref, var 출력</button>
</div>
);
}
export default App;
state 증가, ref 증가, var 증가 각 3회후 출력버튼
state값 증가 (렌더링 유발)
Dom 요소 접근(포커스)
import{useState, useRef, useEffect}from"react";
functionApp() {
constinputRef = useRef();
useEffect(() => {
inputRef.current.focus()
},[])
functionlogin() {
alert(`welcome ${inputRef.current.value}!`)
inputRef.current.focus()
}
return(
<divclassName="App">
<input ref={inputRef}type="text"placeholder="username"/>
<buttononClick={login}>login</button>
</div>
);
}
export defaultApp;
react에서 context api는 앱 안에서 전역적으로 사용되는 데이터들을 여러 컴포넌트들이 공유할 수 있는 방법을 제공해 준다
react에서의 일반적인 데이터 흐름은 부모 컴포넌트에서 자식 컴포넌트로props를 통해 전달된다.
props 대신에 context를 사용해서 데이터를 공유하면 상위 컴포넌트에 있는 데이터를 모든 자녀 컴포넌트들이 useContext를 통해 데이터를 사용할 수 있게 된다.
단, context를 사용하면 컴포넌트를 재사용하기 어려워 질 수 있으므로 반드시 필요한 경우에만 사용한다.
context API를 사용하기 위해서는 Provider
, Consumer
, createContext
이렇게 세가지 개념을 알고 있으면 된다.
createContext
: context 객체를 생성한다.Provider
: 생성한 context를 하위 컴포넌트에게 전달하는 역할을 한다.Consumer
: context의 변화를 감시하는 컴포넌트이다.App.js
import React, { createContext } from "react";
import Children from "./Children";
// AppContext 객체를 생성한다.
export const AppContext = createContext();
const App = () => {
const user = {
name: "박종현",
job: "백수"
};
return (
<>
<AppContext.Provider value={user}>
<div>
<Children />
</div>
</AppContext.Provider>
</>
);
};
export default App;
Children.js
<AppContext.Consumer>
태그로 컴포넌트를 감싸서 컨텍스트 적용import React from "react";
import { AppContext } from "./App";
const Children = () => {
return (
<AppContext.Consumer>
{(user) => (
<>
<h3>AppContext에 존재하는 값의 name은 {user.name}입니다.</h3>
<h3>AppContext에 존재하는 값의 job은 {user.job}입니다.</h3>
</>
)}
</AppContext.Consumer>
);
};
export default Children;
Children.js → useContext 를 적용
import React, { useContext } from "react";
import { AppContext } from "./App";
const Children = () => {
// useContext를 이용해서 따로 불러온다.
const user = useContext(AppContext);
return (
<>
<h3>AppContext에 존재하는 값의 name은 {user.name}입니다.</h3>
<h3>AppContext에 존재하는 값의 job은 {user.job}입니다.</h3>
</>
);
};
export default Children;
App.js 에서 Context를 생성하고 Provider를 통해 전달하는 코드는 그대로
AppContext
를 사용하는 과정이 const user = useContext(AppContext)
를 통해 Context를 불러 온 후 바로 사용이 가능하게 바뀌었다.
따라서 useContext를 사용하면 기존의 Context 사용 방식보다 더 쉽고 간단하게 Context를 사용이 가능하고, 앞서 다뤘던 useState, useEffect와 조합해서 사용하기 쉽다는 장점이 있다