기록
useRef로 변수 관리 본문
useRef는 DOM에 직접 접근할 때 사용한다고 했음
대표적으로 input.focus() 같은 것! -> input.current.focus();
또 하나의 기능이 있는데,
(어떤 용도로 사용하든 .current를 꼭 붙인다는 점!!! 기억하기)
"useRef 로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않습니다.
리액트 컴포넌트에서의 상태는 useState를 호출하고 나서 그 다음 렌더링 이후로 업데이트 된 상태를 조회 할 수 있는 반면, useRef 로 관리하고 있는 변수는 설정 후 바로 조회 할 수 있습니다."
즉, useState를 사용했을 때 값이 변경되면 리렌더가 일어나지만,
useRef를 사용하면 값이 변경돼도 다시 렌더되지 않음.
값이 변하기는 하지만, 화면에는 영향을 주고 싶지 않을 때. useRef를 사용함.
불필요한 렌더를 막기 위해.
그래서 setTimeout, setInterval을 통해 만들어진 id, scroll 위치 등을 이용할 때 useRef 를 사용함.
예제)
상태관리를 부모 컴포넌트(App)에서 하고,
자식 컴포넌트(CreateUser)의 input의 값, 이벤트함수등을 props로 넘겨받게 해보자,
export default function CreateUser({ username, email, onChange, onCreate }) {
return (
<div>
<input
name="username"
placeholder="계정명"
onChange={onChange}
value={username}
/>
<input
name="email"
placeholder="이메일"
onChange={onChange}
value={email}
/>
<button onClick={onCreate}>등록</button>
</div>
);
}
import React from "react";
function User({ user }) {
return (
<div>
<b>{user.username}</b> ({user.email})
</div>
);
}
export default function UserList({ users }) {
return (
<div>
{users.map((v) => (
<User user={v} key={v.id} />
))}
</div>
);
}
import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
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'
},
{
id: 2,
username: 'tester',
email: 'tester@example.com'
},
{
id: 3,
username: 'liz',
email: 'liz@example.com'
}
]);
const nextId = useRef(4);
const onCreate = () => {
const user = {
id: nextId.current,
username,
email
};
setUsers([...users, user]);
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} />
</>
);
}
export default App;
여기서 주목할 포인트는,
const [users, setUsers] = useState([
{
id: 1,
username: 'velopert',
email: 'public.velopert@gmail.com'
},
{
id: 2,
username: 'tester',
email: 'tester@example.com'
},
{
id: 3,
username: 'liz',
email: 'liz@example.com'
}
]);
const nextId = useRef(4);
const onCreate = () => {
const user = {
id: nextId.current,
username,
email
};
setUsers([...users, user]);
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
더미데이터 부분을 기본값(users)로 설정하고 props로 내려보냄.
등록 버튼을 클릭한 순간, 이벤트함수가 실행돼서
input에서 받은 값을 setUsers로 갱신한다는 점!!!!!
불변성 유지를 위해, 초기값 ...users 먼저 받아오고,
이번에 갱신할 값을 user라는 변수에 담아서 추가함.
고유 id는 1씩 추가하는데, 여기서 바로 useRef 가 사용됨!
새 배열에 새 항목을 추가할 때 새 항목에서 사용할 고유 id를 관리하는 용도.
const nextId = useRef(4);
const onCreate = () => {
nextId.current += 1;
useRef()를 사용할 때 파라미터를 넣어주면, 이 값이 .current 값의 기본값이 됨.
그리고 이 값을 수정/조회할 때 .current 값을 수정/조회하면 됨
그럼 삭제를 해보자, 삭제할 때는 filter를 사용한다. 불변성 유지에 적절하기 때문.
현재 컴포넌트 구조
App -> CreateUser
UserList -> User
App에서 상태관리 중이므로, 여기서 onRemove 함수를 만들어서 밑으로 내려보냄. 총 2번 보내야겠지.
//App
const onRemove = (id) => {
setUsers(users.filter((v) => v.id !== id));
};
return (
<>
<UserList users={users} onRemove={onRemove} />
</>
);
}
import React from "react";
function User({ user, onRemove }) {
return (
<div>
<b>{user.username}</b> ({user.email})
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
}
export default function UserList({ users, onRemove }) {
return (
<div>
{users.map((v) => (
<User user={v} key={v.id} onRemove={onRemove} />
))}
</div>
);
}
onRemove라는 props에 삭제하는 함수를 담아서 내려보냄.
그리고 최종 목적지 User에서 클릭한 대상의 id를 입력받아서 다시 UserList로, App으로 올려보냄.
최종 목적지, 최종으로 실행하는 User 컴포넌트에서
그냥 onRemove(user.id)가 아닌, () => onRemove(user.id) 를 입력하는 이유,
onRemove(user.id)를 입력하면 바로 실행되어버리기 때문.
이전전시간에도 정리한 것 같은데,
이벤트함수를 넣는 곳에 () 를 사용하면 () 의미 그대로 함수가 호출돼버림.
호출하면 뭐다? 리턴값을 호출하는것...
리턴하는 값이 없기 때문에 undefined가 나옴..
그래서 그 함수 자체를 입력해야!
그 함수 안에 포함된 onRemove와 파라미터인 user.id를 같이! 위로 전달할 수 있게 됨.
(이전에 정리한 내용)--------------------------------------------------------------
이러한 이벤트함수자리에 showName 이 아니라 showName()을 넣게 되면,
showName함수가 리턴하는 값을 가져오게 됨.
현재 반환하는 값이 없으므로 undefined가 나오겠지.
그래서 괄호를 붙이지 않고 함수이름만 입력한다.
함수를 어딘가에 사용할 때(콜백)
함수이름: 그 함수 그 자체..를 실행...
함수(): 그 함수를 호출->리턴값을 가져옴..
-----------------------------------------------------------------------------------
'React.js > 벨로퍼트와 함께 하는 모던 리액트' 카테고리의 다른 글
CSS Module (0) | 2021.03.02 |
---|---|
Sass (0) | 2021.03.02 |
렌더링! use 시리즈(useEffect, useMemo, useCallback 등) (0) | 2021.03.02 |
누구든지 하는 리액트 - 2 (0) | 2021.01.12 |
react 강의로 시작하기 (0) | 2021.01.09 |