Hooks
이다.1, 앞에 use
를 붙여서 Hooks 기능임을 표시한다.
state라는 것을 사용하기 위한 Hook이다.
함수 컴포넌트에서는 기본적으로 State라는 것을 제공하지 않기 때문에 class 컴포넌트처럼 state를 사용하고 싶으면 userState hook를 사용해야한다.
import React from "react";
function Counter(props) {
let count = 0;
return (
<div>
<p>총 {count}번을 클릭했습니다.</p>
<button onClick={() => count++}>클릭</button>
</div>
);
}
export default Counter;
카운트를 함수의 변수로 선언해서 사용하게 되면 클릭 시 카운트 값을 증가시킬 수는 있지만, 재렌더링
이 일어나지 않아 새로운 카운터 값이 화면에 표시되지 않는다.
이럴 땐, State를 사용해서 값이 바뀔 때 마다 재렌더링 되도록 해야 하는데, 함수 컴포넌트에는 해당 기능이 따로 없어서 useState 를 이용해야함
useState를 노출할 때는 파라미터로 선언할 state 초기값이 들어간다.
class NotificationList extends React.Component {
constructor(props) {
super(props);
this.state = {
notifications: [],
}; // 생성자에서 앞으로 사용할 데이터를 state에 넣어서 초기화한다.
}
이렇게 호출하면 return으로 배열이 나오는데, 배열에는 두 가지 항목이 나온다.
첫 번째 : state로 선언된 변수
두 번쨰 : state의 set함수이다.
import React from "react";
import { useState } from "react";
function Counter(props) {
const [count, setCount] = useState(0);
return (
<div>
<p>총 {count}번을 클릭했습니다.</p>
<button onClick={() => setCount(count+1)}>클릭</button>
</div>
);
}
export default Counter;
버튼이 눌렸을 떄, setCount를 호출해서 카운트 1증가시킨다.
카운터의 값이 변경되면 컴포넌트가 재렌더링 되면서 화면에 새로운 카운트 값이 표시된다.
클래스 컴포넌트에서 setState 함수를 호출해서 state가 업데이트 되고 컴포넌트가 재랜더링되는것이랑 동일하다.
클래스 컴포넌트에서는 setState함수 하나를 사용해서 모든 State의 값을 관리했지만, useState에서는 변수 각각에 대해 set함수가 따로 존재한다.
useEffect(이펙트함수, 의존성배열);
의존성 배열이란 ?
Effect function이 mount, unmount시에 단 한 번씩만 실행된다.
useEffect(이팩트함수,[]);
로 정의하면 된다.[예제]
import React, { useState, useEffect } from "react";
function Counter(props) {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>총 {count}번 실행된다.</p>
<button
onClick={() => {
setCount(count + 1);
}}
></button>
</div>
);
}
export default Counter;
useEffect()
: componentDidMount, componentDidUpdate와 비슷하게 작동한다.
의존성 배열 없이 useEffect를 사용하면 React는 DOM이 변경된 이후에 해당 이펙트 함수를 실행하라는 의미로 받아들인다.
기본적으로 컴포넌트가 처음 렌더링 될 때를 포함해서 매번 렌더링 될 때 마다 이펙트가 발생한다.
이 코드의 경우 이펙트 함수 + 처음 컴포넌트가 마운트 되었을 떄 실행되고 이후 컴포넌트가 업데이트 될 때마다 실행된다.
결과적으로 DidMount + DidUpdate 동일한 역할을 진행한다.
이펙트는 함수 컴포넌트 안
에서 선언되기 때문에 컴포넌트의 props와 state에 접근할 수 있다.
[구독 example (참고)]
import React, { useState, useEffect } from "react";
function UserStatus(props) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status)
{
setIsOnline(status.isOnline);
}
useEffect(()=>{
// 구독
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
return ( // 컴포넌트가 unmount 될 떄 호출된다.
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
// useEffect에서 리턴하는 함수는 컴포넌트가 mount 해제, unmount 될 떄,
);
});
if(isOnline === null)
{
return `대기중....`;
}
return isOnline ? `온라인` : `오프라인`;
}
export default UserStatus;
[내가 해석한 소스리뷰]
useEffect는 상태가 변경되면 실행된다. 현재, 구독시에 useEffect()가 실행되는데,
ServerAPI.subscribeUserStatus는 파라미터로 2개를 받는데,
props.user.id : userStatus의 props
handleStatusChange : 함수호출(콜백)을 실행한다.
handleStatusChange를 실행하여 -> setIsOnline(status.isOnline)을 주입한다.
const[status.isOnline]으로 상태값 변수를 받는다.
그 상태값으로 isOnline === null이면 --> return 처리하고
그게 아니라면 삼항연산자를 통해서 리턴한다.
return ServerAPI.unsubscribeUserStatus 하는 경우
return () =>
함수로 본다. (신기하네..) componentWillUnmount란 무엇인가?
componentWillUnmount() {
// 컴포넌트가 언마운트되기 전에 수행되는 코드
}
만약에 의존성 배열을 추가한다면?
useEffect(() => {
// 구독
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
// 언마운트 시 정리
return () => {
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
};
}, [props.user.id]);
import React, { useState, useEffect } from "react";
const UserStatusWithCounter = () => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
const [isOnline, setIsOnline] = useState(null);
useEffect(()=>{
ServerAPI.subscribeUserStatus(props.user.id, handleStatusChange);
return ( // 컴포넌트가 unmount 될 떄 호출된다.
ServerAPI.unsubscribeUserStatus(props.user.id, handleStatusChange);
// useEffect에서 리턴하는 함수는 컴포넌트가 mount 해제, unmount 될 떄,
);
});
function handleStatusChange(status)
{
setIsOnline(status.isOnline);
}
};
export default UserStatusWithCounter;
출처 | https://velog.io/@velopert/react-hooks#11-usestate-%EB%A5%BC-%EC%97%AC%EB%9F%AC%EB%B2%88-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0 해당 블로그를 정리한 내용입니다.
import React, { useState } from "react";
const Counter = () => {
const [value, setValue] = useState(0);
return (
<div>
<p>
현재 카운터 값은 <b>{value}</b>입니다.
</p>
<button onClick={() => setValue(value + 1)}></button>
{/* 콜백함수 클릭 됐을 떄, 처리 */}
<button onClick={() => setValue(value - 1)}></button>
</div>
);
};
export default Counter;
const [value, setValue] = useState(0);
const array = ['dog','cat','sheep'];
const [first,second] = array;
console.log(first,second);
useState(0)
배열의 첫 번째 원소는 상태값
배열의 두 번쨰 원소는 상태를 설정하는 함수다.
렌더링해보자.
import React, { Fragment } from "react";
import ReactDOM from "react-dom/client";
import "./index.css";
import Counter from "./chapter_07/Counter";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<Counter />
</React.StrictMode>,
document.getElementById("root")
);
import React, { useState } from "react";
const Info = () => {
const [name, setName] = useState("");
const [nickname, setNickname] = useState("");
const onChangeName = (e) => {
setName(e.target.value);
// setter와 같은원리 -> setName함수를 호출하여 name값에 e.tatget.value에 꽂는다.
};
const onChangeNickname = (e) => {
setNickname(e.target.value);
};
return (
<div>
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickname} />
</div>
{/* onChange --> change 될때, onChangeNmae함수가 호출된다.
사용자가 입력할 떄 마다 호출되며, 입력값이 name, nickname 변수에 꽂힌다.
*/}
<div>
<div>
<b>이름 :</b> {name}
</div>
</div>
<div>
<div>
<b>닉네임 :</b> {nickname}
</div>
</div>
</div>
);
};
export default Info;
index.js에 렌더링함
특정 작업을 수행하도록 설정 할 수 있는 Hook
이다.클래스형 컴포넌트의 ComponentDidMount
와 ComponentDidUpdate
를 합친 형태로 보아도 무방하다.
우리가 만든 Info 컴포넌트에 useEffect를 적용해보자.
import React, { useState } from "react";
const Info = () => {
const [name, setName] = useState("");
const [nickname, setNickname] = useState("");
const onChangeName = (e) => {
setName(e.target.value);
// setter와 같은원리 -> setName함수를 호출하여 name값에 e.tatget.value에 꽂는다.
};
const onChangeNickname = (e) => {
setNickname(e.target.value);
};
return (
<div>
<div>
<input value={name} onChange={onChangeName} />
<input value={nickname} onChange={onChangeNickname} />
</div>
{/* onChange --> change 될때, onChangeNmae함수가 호출된다.
사용자가 입력할 떄 마다 호출되며, 입력값이 name, nickname 변수에 꽂힌다.
*/}
<div>
<div>
<b>이름 :</b> {name}
</div>
</div>
<div>
<div>
<b>닉네임 :</b> {nickname}
</div>
</div>
</div>
);
};
export default Info;
기존 코드에서
useEffect(() => {
console.log("렌더링이 완료되었습니다!");
console.log({
name,
nickname,
});
});
이 부분이 추가되었다.
useEffect(() => {
console.log("렌더링이 완료되었습니다!");
console.log({
name,
nickname,
});
}, []);
배열을 넣으면 된다.
클래스형 컴포넌트라면 어떻게 작성할까?
componentDidUpdate(prevProps, prevState)
{
if(prevProps.value !== this.props.value)
{
doSomething();
}
}
props 안에 들어있는 value의 값이 바뀔때에 특정 작업을 수행하도록 되어있다.
만약 이런 작업을 useEffect에서 해야 한다면 어떻게 해야될까?
useEffect의 두 번쨰 파라미터로 전달되는 배열안에 검사하고 싶은 값을 넣어주면 된다.
useEffect(()=>{
console.log(name);
},[name]);
[name] : 배열 안에는 useState를 통해 관리하고 있는 상태를 넣어주면 된다.
props로 전달받은 값을 넣어주어도 된다.
useEffect는 기본적으로 렌더링 되고난 직후마다 실행된다. 두번째 파라미터 배열에 무엇을 넣느냐에 따라 실행되는 조건이 달라진다.
컴포넌트가 언마운트 되기 전이나, 업데이트 되기 직전에 어떠한 작업을 수행하고 싶다면, useEffect에서 뒷정리 함수를 반환해주어야 한다.
마운트 : 처음 나타났을 떄,
언마운트 : 사라졌을 떄,
Info.jsx 추가
useEffect(() => {
console.log('effect');
console.log(name);
return () => {
console.log('cleanup');
console.log(name);
};
});
App.jsx에 추가
import React, { useState } from 'react';
import Info from './Info';
const App = () => {
const [visible, setVisible] = useState(false);
return (
<div>
<button
onClick={() => {
setVisible(!visible);
}}
>
{visible ? '숨기기' : '보이기'}
</button>
<hr />
{visible && <Info />}
</div>
);
};
export default App;
[내가 해석한 소스리뷰]
보이기를 클릭 했을 때, Info 컴포넌트를 렌더링하여 보여준다.
{visible ? '숨기기' : '보이기'}
삼항연산자로 숨기기와 보이기를 둘 중에 하나를 클릭한 결과를 visible에 담는다.
{visible && <Info />}
이 부분은 보이기를 클릭했을 때,
'보이기' && <Info/>
로 해석할 수 있다. Info부분을 화면에 렌더링함.[몰랐던 부분]
setVisible(!visible); 를 통해서 visible 상태가 토글된다.
{visible && } : visible이 true일 떄만 를 렌더링한다.
숨기기
버튼을 클릭하면 , 컴포넌트가 언마운트된다. + 이 떄 useEffect의 cleanUp 부분이 실행된다.
useState: 함수 컴포넌트에서 상태를 관리하는데 사용한다.
useEffect는 "부수효과"를 다루기 위해 사용된다.
[결과]
컴포넌트가 나타날 떄 콘솔에 effect가 보이고, 사라질 때, cleanUp이 보여지게 된다.
한 번 인풋에 이름을 적어보고 어떤 결과가 나타나는지 확인해보자.
렌더링이 될 떄 마다, 뒷정리 함수
가 계속 보여지고 있다. 그리고 뒷정리함수가 호출될 때에는 업데이트 되기 직전의 값을 보여주고 있다.
만약에 언마운트 될 때만 함수를 호출하고 싶다면, useEffect함수의 두 번쨰 파라미터에 비어있는 배열을 넣으면 된다.
Info.jsx - useEffect
useEffect(()=>{
console.log('effect');
console.log(name);
return () => {
console.log('cleanup');
console.log(name);
};
}, []);
함수형 컴포넌트에서 Context를 쉽게 사용할 수 있다.
src 디렉토리에 ContextSample.jsx라는 컴포넌트를 만들어보자.
import React, { createContext, useContext } from 'react';
const ThemeContext = createContext('black');
const ContextSample = () => {
const theme = useContext(ThemeContext);
const style = {
width: '24px',
height: '24px',
background: theme
};
return <div style={style} />;
};
export default ContextSample;
다 만들었다면 App 컴포넌트에서 렌더링을 진행하자.
import React from 'react';
import ContextSample from './ContextSample';
const App = () => {
return <ContextSample />;
};
export default App;