Section 12: React - Behind the Scenes - How React Works
The goals
πͺπ»How Does React Work Behind The Scenes?
βπ»Understanding the Virtual DOM & DOM Updates
ππ»Understanding State & State Updates
useMemo λ₯Ό μ¬μ©νμ¬ μ°μ°ν κ° μ¬μ¬μ©νκΈ°
μ΄λ²μλ μ±λ₯ μ΅μ νλ₯Ό μνμ¬ μ°μ°λ κ°μ useMemoλΌλ Hook μ μ¬μ©νμ¬ μ¬μ¬μ©νλ λ°©λ²μ μμ보λλ‘ νκ² μ΅λλ€.
App μ»΄ν¬λνΈμμ λ€μκ³Ό κ°μ΄ countActiveUsers λΌλ ν¨μλ₯Ό λ§λ€μ΄μ, active κ°μ΄ true μΈ μ¬μ©μμ μλ₯Ό μΈμ΄μ νλ©΄μ λ λλ§μ ν΄λ³΄μΈμ.
App.js
import React, { useRef, useState } 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 = e => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value
});
};
const [users, setUsers] = useState([
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com',
active: true
},
{
id: 2,
username: 'tester',
email: 'tester@example.com',
active: false
},
{
id: 3,
username: 'liz',
email: 'liz@example.com',
active: false
}
]);
const nextId = useRef(4);
const onCreate = () => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
const onRemove = id => {
// user.id κ° νλΌλ―Έν°λ‘ μΌμΉνμ§ μλ μμλ§ μΆμΆν΄μ μλ‘μ΄ λ°°μ΄μ λ§λ¬
// = user.id κ° id μΈ κ²μ μ κ±°ν¨
setUsers(users.filter(user => user.id !== id));
};
const onToggle = id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
};
const count = countActiveUsers(users);
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
<div>νμ±μ¬μ©μ μ : {count}</div>
</>
);
}
export default App;
countActiveUsers ν¨μμμ μ½μμ λ©μμ§λ₯Ό μΆλ ₯νλλ‘ ν μ΄μ λ, μ΄ ν¨μκ° νΈμΆλ λλ§λ€ μ°λ¦¬κ° μμμκ² νκΈ° μν¨μ λλ€.
ꡬνμ λ§μΉλ©΄ λ€μκ³Ό κ°μ΄ λνλ ν λ°μ.
λ€λ₯Έ κ³μ λͺ μ λλ¬μ μ΄λ‘μμΌλ‘ λ§λ€λ©΄ νμ± μ¬μ©μ μ λν μ λ°μ΄νΈ λ κ²μ λλ€.
κ·Έλ°λ°, μ¬κΈ°μ λ°μνλ μ±λ₯μ λ¬Έμ κ° νκ°μ§ μμ΅λλ€. λ°λ‘, input μ κ°μ λ°κΏλμλ countActiveUsers ν¨μκ° νΈμΆλλ€λ κ² μ λλ€.
νμ± μ¬μ©μ μλ₯Ό μΈλ건, users μ λ³νκ° μμλλ§ μΈμΌλλ건λ°, input κ°μ΄ λ°λ λμλ μ»΄ν¬λνΈκ° 리λ λλ§ λλ―λ‘ μ΄λ κ² λΆνμν λμλ νΈμΆνμ¬μ μμμ΄ λλΉλκ³ μμ΅λλ€.
μ΄λ¬ν μν©μλ useMemo λΌλ Hook ν¨μλ₯Ό μ¬μ©νλ©΄ μ±λ₯μ μ΅μ ν ν μ μμ΅λλ€.
Memo λ "memoized" λ₯Ό μλ―Ένλλ°, μ΄λ, μ΄μ μ κ³μ° ν κ°μ μ¬μ¬μ©νλ€λ μλ―Έλ₯Ό κ°μ§κ³ μμ΅λλ€.
νλ² μ¬μ©ν΄λ³ΌκΉμ?
App.js
import React, { useRef, useState, useMemo } 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 = e => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value
});
};
const [users, setUsers] = useState([
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com',
active: true
},
{
id: 2,
username: 'tester',
email: 'tester@example.com',
active: false
},
{
id: 3,
username: 'liz',
email: 'liz@example.com',
active: false
}
]);
const nextId = useRef(4);
const onCreate = () => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
const onRemove = id => {
// user.id κ° νλΌλ―Έν°λ‘ μΌμΉνμ§ μλ μμλ§ μΆμΆν΄μ μλ‘μ΄ λ°°μ΄μ λ§λ¬
// = user.id κ° id μΈ κ²μ μ κ±°ν¨
setUsers(users.filter(user => user.id !== id));
};
const onToggle = id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
};
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;
useMemo μ 첫λ²μ§Έ νλΌλ―Έν°μλ μ΄λ»κ² μ°μ°ν μ§ μ μνλ ν¨μλ₯Ό λ£μ΄μ£Όλ©΄ λκ³ λλ²μ§Έ νλΌλ―Έν°μλ deps λ°°μ΄μ λ£μ΄μ£Όλ©΄ λλλ°, μ΄ λ°°μ΄ μμ λ£μ λ΄μ©μ΄ λ°λλ©΄, μ°λ¦¬κ° λ±λ‘ν ν¨μλ₯Ό νΈμΆν΄μ κ°μ μ°μ°ν΄μ£Όκ³ , λ§μ½μ λ΄μ©μ΄ λ°λμ§ μμλ€λ©΄ μ΄μ μ μ°μ°ν κ°μ μ¬μ¬μ©νκ² λ©λλ€.
νλ² κ³μ λͺ λ€μ ν΄λ¦λ ν΄λ³΄κ³ , input μ μμ λ ν΄λ³΄μΈμ.
κ·ΈλΌ μ΅μ νμ λ©λͺ¨λ¦¬ μ¬μ©μ μ μ½νκΈ° μν λ°©μμΌλ‘ useMemoλ₯Ό μ무곳μλ μ¬μ©ν μ μμ§ μμκΉ?
λ΅μ nej
μ΅μ νλ₯Ό ν΄μ£Όλ λμ μ μ΄λμ λμ λΉμ©μ΄ μꡬλ¨.
κ·Έ λΉμ©μ΄λΌνλ©΄ μ΄μ propsκ°μ κΈ°μ΅νκ³ μμ΄μΌ νλ€λ κ²κ³Ό λΉκ΅λ₯Ό νλ λμμ ν΄μΌ νλ€λ κ²!
useCallback μ μ¬μ©νμ¬ ν¨μ μ¬μ¬μ©νκΈ°
useCallback μ μ°λ¦¬κ° μ§λ μκ°μ λ°°μ λ useMemo μ λΉμ·ν Hook μ λλ€.
useMemo λ νΉμ κ²°κ³Όκ°μ μ¬μ¬μ© ν λ μ¬μ©νλ λ°λ©΄, useCallback μ νΉμ ν¨μλ₯Ό μλ‘ λ§λ€μ§ μκ³ μ¬μ¬μ©νκ³ μΆμλ μ¬μ©ν©λλ€.
μ΄μ μ App.js μμ ꡬννμλ onCreate, onRemove, onToggle ν¨μλ₯Ό νμΈν΄λ΄ μλ€.
const onCreate = () => {
const user = {
id: nextId.current,
username,
email
};
setUsers(users.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
const onRemove = id => {
// user.id κ° νλΌλ―Έν°λ‘ μΌμΉνμ§ μλ μμλ§ μΆμΆν΄μ μλ‘μ΄ λ°°μ΄μ λ§λ¬
// = user.id κ° id μΈ κ²μ μ κ±°ν¨
setUsers(users.filter(user => user.id !== id));
};
const onToggle = id => {
setUsers(
users.map(user =>
user.id === id ? { ...user, active: !user.active } : user
)
);
};
μ΄ ν¨μλ€μ μ»΄ν¬λνΈκ° 리λ λλ§ λ λ λ§λ€ μλ‘ λ§λ€μ΄μ§λλ€. ν¨μλ₯Ό μ μΈνλ κ² μ체λ μ¬μ€ λ©λͺ¨λ¦¬λ, CPU λ 리μμ€λ₯Ό λ§μ΄ μ°¨μ§ νλ μμ μ μλκΈ° λλ¬Έμ ν¨μλ₯Ό μλ‘ μ μΈνλ€κ³ ν΄μ κ·Έ μ체 λ§μΌλ‘ ν° λΆνκ° μκΈΈμΌμ μμ§λ§, νλ² λ§λ ν¨μλ₯Ό νμν λλ§ μλ‘ λ§λ€κ³ μ¬μ¬μ©νλ κ²μ μ¬μ ν μ€μν©λλ€.
κ·Έ μ΄μ λ, μ°λ¦¬κ° λμ€μ μ»΄ν¬λνΈμμ props κ° λ°λμ§ μμμΌλ©΄ Virtual DOM μ μλ‘ λ λλ§νλ κ² μ‘°μ°¨ νμ§ μκ³ μ»΄ν¬λνΈμ κ²°κ³Όλ¬Όμ μ¬μ¬μ© νλ μ΅μ ν μμ μ ν 건λ°μ, μ΄ μμ μ νλ €λ©΄, ν¨μλ₯Ό μ¬μ¬μ©νλκ²μ΄ νμμ λλ€.
useCallback μ μ΄λ°μμΌλ‘ μ¬μ©ν©λλ€.
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: 'public.velopert@gmail.com',
active: true
},
{
id: 2,
username: 'tester',
email: 'tester@example.com',
active: false
},
{
id: 3,
username: 'liz',
email: 'liz@example.com',
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 => {
// user.id κ° νλΌλ―Έν°λ‘ μΌμΉνμ§ μλ μμλ§ μΆμΆν΄μ μλ‘μ΄ λ°°μ΄μ λ§λ¬
// = user.id κ° 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;
μ£Όμ νμ€ μ μ, ν¨μ μμμ μ¬μ©νλ μν νΉμ props κ° μλ€λ©΄ κΌ, deps λ°°μ΄μμ ν¬ν¨μμΌμΌ λλ€λ κ² μ λλ€. λ§μ½μ deps λ°°μ΄ μμ ν¨μμμ μ¬μ©νλ κ°μ λ£μ§ μκ² λλ€λ©΄, ν¨μ λ΄μμ ν΄λΉ κ°λ€μ μ°Έμ‘°ν λ κ°μ₯ μ΅μ κ°μ μ°Έμ‘° ν κ²μ΄λΌκ³ 보μ₯ ν μ μμ΅λλ€. props λ‘ λ°μμ¨ ν¨μκ° μλ€λ©΄, μ΄ λν deps μ λ£μ΄μ£Όμ΄μΌ ν΄μ.
μ¬μ€, useCallback μ useMemo λ₯Ό κΈ°λ°μΌλ‘ λ§λ€μ΄μ‘μ΅λλ€. λ€λ§, ν¨μλ₯Ό μν΄μ μ¬μ© ν λ λμ± νΈνκ² ν΄μ€ κ² λΏμ΄μ§μ. μ΄λ°μμΌλ‘λ νν ν μ μμ΅λλ€.
const onToggle = useMemo(
() => () => {
/* ... */
},
[users]
);
useCallback μ μ¬μ© ν¨μΌλ‘μ¨, λ°λ‘ μ΄λ€λΌμ μλ λμ λλ μ΅μ νλ μμ΅λλ€. λ€μ μμμμ, μ»΄ν¬λνΈ λ λλ§ μ΅μ ν μμ μ ν΄μ£Όμ΄μΌλ§ μ±λ₯μ΄ μ΅μ νλλλ°μ, κ·Έ μ μ, μ΄λ€ μ»΄ν¬λνΈκ° λ λλ§λκ³ μλμ§ νμΈνκΈ° μν΄μ React DevTools λΌλ κ²μ μκ°λλ¦¬κ² μ΅λλ€.
μ°μ , ꡬκΈμ React DevTools λ₯Ό κ²μν΄μ ν¬λ‘¬ μΉμ€ν μ΄μ λ€μ΄κ°λ€, ν¬λ‘¬ νμ₯ νλ‘κ·Έλ¨μ μ€μΉν΄μ£ΌμΈμ. λ§ν¬
μ€μΉλ₯Ό νκ³ λλ©΄ λ€μκ³Ό κ°μ΄ React νμ΄ κ°λ°μ λꡬμ λΉλλ€. ν±λλ°ν΄ μμ΄μ½μ λλ₯΄κ³ , 'Highlight Updates' λ₯Ό 체ν¬ν΄μ£ΌμΈμ.
μ΄ μμ±μ ν€λ©΄ λ€μκ³Ό κ°μ΄ 리λ λλ§ λλ μ»΄ν¬λνΈμ μ¬κ°ν ννλ‘ νμ΄λΌμ΄νΈλμ΄ λ³΄μ¬μ§κ² λ©λλ€.
μ§κΈ 보면, input μ΄ λ°λ λμλ UserList μ»΄ν¬λνΈκ° 리λ λλ§μ΄ λκ³ μμ§μ?
λ€μ μμμμλ μ΄ λ¦¬λ λλ§μ λ§μ보λλ‘ νκ² μ΅λλ€.
Summary 1.
React -> usually we work with Functional Component which returns JSX syntax
Props-> we can give props to each component
Whenever we change the state of component, the componenet will be re-evaluated -> the component function executes again
React just brings the latest screen shot and compare it to previous one and if there is some differeces then React deliver it to React DOM because we are using React DOM to render the files.
When we re-evaluate, we run the codes again at the same time functions also + output JSX syntax also.
So to prevent unneccessory re-execution of code, we can use 'React.memo'
but some case that we set the relative value with using '=' then it can't be controlled by 'React.memo', then we can use 'useCallback'
Then every time if the App functions runs again whenever the state changes, doesn't this mean that we will re-initialize our code? and re-execute 'useState' over and over again?
Sources
https://react.vlpt.us/basic/17-useMemo.html
17. useMemo λ₯Ό μ¬μ©νμ¬ μ°μ°ν κ° μ¬μ¬μ©νκΈ° · GitBook
17. useMemo λ₯Ό μ¬μ©νμ¬ μ°μ°ν κ° μ¬μ¬μ©νκΈ° μ΄λ²μλ μ±λ₯ μ΅μ νλ₯Ό μνμ¬ μ°μ°λ κ°μ useMemoλΌλ Hook μ μ¬μ©νμ¬ μ¬μ¬μ©νλ λ°©λ²μ μμ보λλ‘ νκ² μ΅λλ€. App μ»΄ν¬λνΈμμ λ€μκ³Ό κ°μ΄ co
react.vlpt.us
https://academind.com/tutorials/reference-vs-primitive-values
Reference vs Primitive Values
Learn why most people copy objects and arrays in JavaScript incorrectly. And why you won't make that mistake!
academind.com
https://velog.io/@ggong/useState-Hook%EA%B3%BC-%ED%81%B4%EB%A1%9C%EC%A0%80
useState Hookκ³Ό ν΄λ‘μ
μ μ κΈ°μ λ©΄μ μ 보면μ "React hookμμ ν΄λ‘μ κ° μ΄λ»κ² μ°μ΄λμ§ μ€λͺ ν΄λ³΄μΈμ" λΌλ μ§λ¬Έμ λ°μ μ μ΄ μμλ€. λλ¦ λ¦¬μ‘νΈλ₯Ό μ€λ μΌλ€κ³ μκ°νλλ°, ν΄λ‘μ μ λν΄μλ λ°©κΈ μ€λͺ νλλ°..
velog.io
https://yeoulcoding.tistory.com/149#recentEntries
[React] ν΄λ‘μ μ useState Hooks
Overview React Hooksλ React Functional Component(ν¨μν μ»΄ν¬λνΈ)μμ μνκ΄λ¦¬ λ° μ»΄ν¬λνΈ μλͺ μ£ΌκΈ° API(Lifecycle API) λ± ν΄λμ€ μ»΄ν¬λνΈμμλ§ μ§μνλ κΈ°λ₯λ€μ μ¬μ©ν μ μλλ‘ λμμ€λλ€. ν¨μν
yeoulcoding.me