React.js - 2
useEffect를 사용하여 마운트/언마운트/업데이트 시 할 작업 설정하기
-첫번째 파라미터에는 함수, 두번째 파라미터에는 의존값이 들어있는 배열(deps)을 넣음.
마운트/언마운트
마운트: 처음 나타났을 때
-props로 받은 값을 컴포넌트의 로컬 상태로 설정
-외부 API 요청
-라이브러리 사용
-setInterval를 이용한 반복작업 또는 setTimeout을 통한 작업 예약
언마운트: 사라질 때
-setInterval, setTimeout 이용하여 등록한 작업 clear하기
-라이브러리 인스턴스 제거
cleanup함수: useEffect에서 반환하는 함수. deps가 비어있는 경우 컴포넌트가 사라질 때 호출.
업데이트: 특정 props가 바뀔 때
deps에 특정 값 넣기
-컴포넌트가 처음 마운트 될 때도, 지정한 값이 바뀔 때에도 호출이 됨. 또한 언마운트시에도 호출이 되고, 값이 바뀌기 직전에도 호출이 됨.
deps 파라미터를 생략하기
-컴포넌트가 리렌더링 될 때마다 호출.(부모 컴포넌트가 리렌더링 되면 자식 컴포넌트도 리렌더링 됨.)
수정한 UserList.js 코드
import React, { useEffect } from 'react';
function User({ user, onRemove, onToggle }) {
useEffect(() => {
console.log(user);
});
return (
<div>
<b
style={{
cursor: 'pointer',
color: user.active ? 'green' : 'black'
}}
onClick={() => onToggle(user.id)}
>
{user.username}
</b>
<span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
}
function UserList({ users, onRemove, onToggle }) {
return (
<div>
{users.map(user => (
<User
user={user}
key={user.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
);
}
export default UserList;
useMemo를 사용하여 연산한 값 재사용하기
-이전에 계산한 값을 재사용함으로써 불필요한 호출을 줄여 자원 낭비를 줄임.
-첫번째 파라미터에는 어떻게 연산할지 정의하는 함수를, 두번째 파라미터에는 dpes 배열을 넣어줌.
useCallback을 사용하여 함수 재사용하기
-특정 함수를 새로 만들지 않고 재사용하고 싶을 때 사용.
-함수 안에서 사용하는 상태 혹은 props가 있다면 (deps)배열 안에 포함시켜야 함. props로 받아온 함수가 있다면 또한 (deps)에 넣어주어야 함.
수정한 App.js 코드
import React, { useRef, useState, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
function countActiveUsers(users) {
console.log('활성 사용자 수를 세는중...');
return users.filter(user => user.active).length;
}
function App() {
const [inputs, setInputs] = useState({
username: '',
email: ''
});
const { username, email } = inputs;
const onChange = useCallback(
e => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value
});
},
[inputs]
);
const [users, setUsers] = useState([
{
id: 1,
username: 'velopert',
email: '[email protected]',
active: true
},
{
id: 2,
username: 'tester',
email: '[email protected]',
active: false
},
{
id: 3,
username: 'liz',
email: '[email protected]',
active: false
}
]);
const nextId = useRef(4);
const onCreate = useCallback(() => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
}, [users, username, email]);
const onRemove = useCallback(
id => {
setUsers(users.filter(user => user.id !== id));
},
[users]
);
const onToggle = useCallback(
id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
},
[users]
);
const count = useMemo(() => countActiveUsers(users), [users]);
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
<div>활성사용자 수 : {count}</div>
</>
);
}
export default App;
React.memo를 사용한 컴포넌트 리렌더링 방지
컴포넌트의 props가 바뀌지 않았다면 리렌더링을 방지하여 컴포넌트의 리렌더링 성능을 최적화 시켜줄 수 있음.
함수형 업데이트
콜백함수의 파라미터에서 최신 값을 참조할 수 있으므로 deps배열에 파라미터를 넣지 않아도 됨.
useReducer를 사용하여 상태 업데이트 로직 분리하기
useReducer 이해하기
-컴포넌트의 상태 업데이트 로직을 컴포넌트에서 분리시킬 수 있음.
-reducer: 현재 상태와 액션 객체를 파라미터로 받아와서 새로운 상태를 반환해줌.
function reducer(state, action) {
return nextState;
}
action은 주로 type값을 지닌 객체형태이지만 자유로움.
-useReducer
const [state, dispatch] = useReducer(reducer, initialState);
state는 우리가 앞으로 컴포넌트에서 사용할 수 있는 상태, dispatch는 액션을 발생시키는 함수
App컴포넌트를 useReducer로 구현하기
import React, { useRef, useReducer, useMemo, useCallback } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
function countActiveUsers(users) {
console.log('활성 사용자 수를 세는중...');
return users.filter(user => user.active).length;
}
const initialState = {
inputs:{
username: '',
email: ''
},
users:[
{
id: 1,
username: 'velopert',
email: '[email protected]',
active: true
},
{
id: 2,
username: 'tester',
email: '[email protected]',
active: false
},
{
id: 3,
username: 'liz',
email: '[email protected]',
active: false
}]
}
function reducer(state, action){
switch(action.type){
case 'CHANGE_INPUT':
return{
...state,
inputs: {
...state.inputs,
[action.name]: action.value
}
};
case 'CREATE_USER':
return{
inputs: initialState.inputs,
users: state.users.concat(action.user)
};
case 'TOGGLE_USER':
return{
...state,
users: state.users.map(user =>
user.id === action.id ? { ...user, active: !user.active } : user
)
};
case 'REMOVE_USER':
return{
...state,
users: state.users.filter(user => user.id !== action.id)
}
default:
return state;
}
}
function App(){
const[state, dispatch] = useReducer(reducer, initialState);
const nextId = useRef(4);
const {users} = state;
const{username, email} = state.inputs;
const onChange = useCallback(e => {
const { name, value } = e.target;
dispatch({
type: 'CHANGE_INPUT',
name,
value
});
}, []);
const onCreate = useCallback(() => {
dispatch({
type: 'CREATE_USER',
user: {
id: nextId.current,
username,
email
}
});
nextId.current += 1;
}, [username, email]);
const onToggle = useCallback(id => {
dispatch({
type: 'TOGGLE_USER',
id
});
}, []);
const onRemove = useCallback(id => {
dispatch({
type: 'REMOVE_USER',
id
});
}, []);
const count = useMemo(() => countActiveUsers(users), [users]);
return(
<>
<CreateUser username = {username} email = {email} onChange = {onChange} onCreate ={onCreate} />
<UserList users={users} onToggle = {onToggle} onRemove = {onRemove} />
<div>활성사용자수: {count} </div>
</>
);
};
export default App;
커스텀 Hooks 만들기
-반복되는 로직을 쉽게 재사용.
-Hooks를 사용하여 원하는 기능을 구현해주고, 컴포넌트에서 사용하고 싶은 값들을 반환.
커스텀 hooks로 만들어준 useInput.js
import {useState, useCallback} from 'react';
function useInputs(initialForm){
const[form, setForm] = useState(initialForm);
const onChange = useCallback((e)=>{
const {name, value} = e.target;
setForm(form => ({...form, [name]: value}));
},[]);
const reset = useCallback(()=> setForm(initialForm), [initialForm]);
return [form, onChange, reset];
};
export default useInputs;
Context API를 사용하여 전역값 관리
새로운 context 만들기
-React.createContext() 함수 사용
const UserDispatch = React.createContext(null);
-Context를 만들면, Context 안에 Provider 라는 컴포넌트가 들어있고, 이 컴포넌트를 통하여 Context 의 값을 정할 수 있음.
useState vs useReducer
useReducer를 사용하면 Context API를 사용해서 dispatch를 전역적으로 사용 할 수 있게 해주어 컴포넌트에게 함수를 전달해줘야 하는 상황에서 코드의 구조가 훨씬 깔끔해짐.
Immer를 사용한 더 쉬운 불변성 관리
-우리가 상태를 업데이트할 때 불변성을 신경쓰지 않으면서 업데이트해줄 수 있음.
import produce from 'immer';
produce라는 이름으로 immer를 불러옴. produce함수에 첫번째 파라미터로는 수정하고 싶은 상태, 두번째 파라미터에는 어떻게 업데이트하고 싶을지 정의하는 함수.
-함수형 업데이트를 사용하는 경우에는 더 편하게 코드를 작성할 수도 있는데, produce함수에서 첫번째 파라미터를 생략하고 업데이트 함수를 넣어주면 반환값은 상태를 업데이트해주는 함수가 됨.
클래스형 컴포넌트
-render()메서드: 렌더링 하고 싶은 JSX를 반환.
-props를 조회할 때는 this.props를 조회.
커스컴 메서드 만들기
-클래스 안에 메서드 선언.
-상태를 업데이트할 때는 this.setStat함수 사용.
메서드와 컴포넌트 인스턴스 사이의 관계가 끊기지 않도록 하는 방법
-클래스의 생성자 메서드 constructor에서 bind작업을 해주는 것
-커스텀 메서드를 선언 할 때 화살표 함수 문법을 사용
-onClick에서 새로운 함수를 만들어서 전달
상태 선언하기
state를 선언 할 때에는 constructor내부에서 this.state 를 설정, 무조건 객체 형태.
setState의 함수형 업데이트
setState 는 단순히 상태를 바꾸는 함수가 아니라 상태로 바꿔달라고 요청해주는 함수로 이해해야 함.
LifeCycle Method
-컴포넌트가 브라우저상에 나타나고, 업데이트되고, 사라지게 될 때, 에러가 났을 때 호출되는 메서드
-클래스형 컴포넌트에서만 사용할 수 있음.
마운트
마운트될 때 발생하는 생명주기
-constructor: 컴포넌트의 생성자 메서드. 가장 먼저 실행
-getDerivedStateFromProps: props로 받아온 것을 state에 넣어주고 싶을 때 사용. 앞에 static을 필요로 하고, 이 안에서는 this를 조회 할 수 없음
-render: 컴포넌트를 렌더링하는 메서드
-componentDidMount: 컴포넌트의 첫번째 렌더링이 마치고 나면 호출되는 메서드
업데이트
-getDerivedStateFromProps
-shouldComponentUpdate: 컴포넌트가 리렌더링 할지 말지를 결정하는 메서드
-render
-getSnapshotBeforeUpdate: 컴포넌트에 변화가 일어나기 직전의 DOM 상태를 가져와, 특정 값을 반환하면 그 다음 발생하게 되는 componentDidUpdate함수에서 받아와서 사용 가능.
-componentDidUpdate: 리렌더링을 마치고 화면에 우리가 원하는 변화가 모두 반영되고 난 뒤 호출되는 메서드
언마운트
-componentWillUnmount: 컴포넌트가 화면에서 사라지기 직전에 호출.
componentDidCatch
-에러 처리(props를 전달하지 않아 생기는 등)
-첫번째 파라미터에서 에러의 내용, 두번째 파라미터에서 에러가 발생한 위치를 알려줌.
Author And Source
이 문제에 관하여(React.js - 2), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@jgyeyang/React.js-2저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)