useRef
- ref: 리액트에서 특정 DOM을 선택할 때 사용
- 함수형 컴포넌트에서 ref을 사용할 때에 useRef라는 Hook을 사용함
import React, { useState, useRef } from 'react';
const InputSample = () => {
const [inputs, setInputs] = useState({
name: '',
nickname: ''
});
const nameInput = useRef();
const { name, nickname } = inputs; // 비구조화 할당을 통해 값 추출
const onChange = (e) => {
const { value, name } = e.target; // 우선 e.target 에서 name 과 value 를 추출
setInputs({
...inputs, // 기존의 input 객체를 복사한 뒤
[name]: value // name 키를 가진 값을 value 로 설정
});
};
const onReset = () => {
setInputs({
name: '',
nickname: ''
});
nameInput.current.focus();
};
return (
<div>
<input
name="name"
placeholder="이름"
onChange={onChange}
value={name}
ref={nameInput}
/>
<input
name="nickname"
placeholder="닉네임"
onChange={onChange}
value={nickname}
/>
<button onClick={onReset}>초기화</button>
<div>
<b>값: </b>
{name} ({nickname})
</div>
</div>
);
}
export default InputSample;
- useRef()를 사용하여 Ref 객체를 만들고, 이것을 선탁할 DOM에 ref값으로 설정해주면 Ref의 객체의 .corrent 값은 해당 DOM을 가리키게 됨
배열 렌더링하기
// 렌더링할 배열
const users = [
{
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'
}
];
- 재사용하는 코드를 일일히 넣지 않기 위해 컴포넌트를 재사용할 수 있도록 새로 만들기 (여러 컴포넌트 선언 가능)
- 인덱스 하나하나 조회하는 방법은 동적인 배열을 렌더링하지 못함 -> map() 사용
- map(): 배열 안에 있는 각 원소를 변환하여 새로운 배열을 만들어줌 (일반 데이터 배열 -> 리액트 엘리먼트 배열)
import React from 'react';
const User = ({ user }) => (
<div>
<b>{user.username}</b> <span>({user.email})</span>
</div>
);
const UserList = () => {
const users = [
{
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'
}
];
return (
<div>
{users.map(user => (
<User user={user} />
))}
</div>
);
}
export default UserList;
- 콘솔에서 에러 발생 -> key 라는 props 설정 필요
- key: 각 원소들마다 가지고 있는 고유값 (ex: id)
import React from 'react';
const User = ({ user }) => (
<div>
<b>{user.username}</b> <span>({user.email})</span>
</div>
);
const UserList = () => {
const users = [
{
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'
}
];
return (
<div>
{users.map(user => (
<User user={user} key={user.id} />
))}
</div>
);
}
export default UserList;
- key 좋은점
useRef 로 컴포넌트 안에 변수 만들기
- 컴포넌트 안에서 조회 및 수정할 수 있는 변수 관리
- setTimeout, setInterveal 통해 만들어진 id, 외부 라이브러리를 사용하여 생성된 인스턴스, scroll 위치 관리 가능
<배열에 추가한 새 항목에서 사용할 고유 id 관리>
- App에서 배열 선언 -> UserList에 props로 전달
//App.js
import React from 'react';
import UserList from './UserList';
const App = () => {
const users = [
{
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'
}
];
return <UserList users={users} />;
}
export default App;
//UserList.js
import React from 'react';
const User = ({ user }) => {
return (
<div>
<b>{user.username}</b> <span>({user.email})</span>
</div>
);
}
function UserList({ users }) {
return (
<div>
{users.map(user => (
<User user={user} key={user.id} />
))}
</div>
);
}
export default UserList;
- App에서 nextId 변수 생성
import React, { useRef } from 'react';
import UserList from './UserList';
const App = () => {
const users = [
{
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 = () => {
// 나중에 구현할 배열에 항목 추가하는 로직
// ...
nextId.current += 1;
};
return <UserList users={users} />;
}
export default App;
배열에 항목 추가하기
- src 디렉토리에 CreateUser.js 컴포넌트 생성
//CreateUser.js
import React from 'react';
const 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>
);
}
export default CreateUser;
- App.js
import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
const 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 = () => {
// 나중에 구현 할 배열에 항목 추가하는 로직
// ...
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} />
</>
);
};
export default App;
- 배열에 새 항목 추가
-- 불변성 지켜주기 (push, splice, sort 등 함수 사용 금지, 사용 시 기존 배열 복사 후 사용)
-- 1. spread 연산자 사용
import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
const 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;
--- setUsers([...users, user]); '...user' 는 기존 'users'의 모든 요소를 복사하고 그 뒤에 새로운 user 객체를 추가하여 새로운 배열을 만듦
-- 2. concat 함수 사용
import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
const 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.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} />
</>
);
};
export default App;
--- setUsers(users.concat(user)); 기존 'users' 배열에 새로 생성된 'user' 객체를 추가하여 새로운 배열을 반환 -> 'setUsers' 는 이 새로운 배열로 상태를 업데이트
배열에 항목 제거하기
- 삭제 버튼 렌더링
// UserList.js
import React from 'react';
const User = ({ user, onRemove }) => {
return (
<div>
<b>{user.username}</b> <span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
};
const UserList = ({ users, onRemove }) => {
return (
<div>
{users.map((user) => (
<User user={user} key={user.id} onRemove={onRemove} />
))}
</div>
);
};
export default UserList;
- onRemove: 해당 id인 객체 삭제하는 역할, 불변성 지켜주기 (ex:filter 배열 내장 함수 사용)
// App.js
import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
const 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.concat(user));
setInputs({
username: '',
email: ''
});
nextId.current += 1;
};
const onRemove = (id) => {
// user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
// = user.id 가 id 인 것을 제거함
setUsers(users.filter((user) => user.id !== id));
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onRemove={onRemove} />
</>
);
};
export default App;
배열 항목 수정하기
- 계정명 클릭 시 초록색 됨 -> 다시 눌렀을 때 검정색 됨
- App 컴포넌트의 users 배열 안의 객체 안에 active 속성 추가
// App.js
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',
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));
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
</>
);
}
export default App;
- active: 사용자가 활성화 상태인지 비활성화 상태인지 표시 -> 시각적으로 표현 가능
- 폰트 색상 바뀌도록 구현 & cursor 설정 (마우스 올렸을 때 손가락 모양으로 변하도록)
// UserList.js
import React from 'react';
function User({ user, onRemove }) {
return (
<div>
<b
style={{
cursor: 'pointer',
color: user.active ? 'green' : 'black'
}}
>
{user.username}
</b>
<span>({user.email})</span>
<button onClick={() => onRemove(user.id)}>삭제</button>
</div>
);
}
function UserList({ users, onRemove }) {
return (
<div>
{users.map(user => (
<User user={user} key={user.id} onRemove={onRemove} />
))}
</div>
);
}
export default UserList;
- onToggle: 사용자의 'active' 상태 전환하는 데 사용
id 값을 비교해서 id가 다르다면 그대로 두고 같다면 active 값을 반전시키도록 구현
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',
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
)
);
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
/>
<UserList users={users} onRemove={onRemove} onToggle={onToggle} />
</>
);
}
export default App;
// UserList.js
import React from 'react';
function User = ({ user, onRemove, onToggle }) => {
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;
'WINK-(Web & App) > React.js 스터디' 카테고리의 다른 글
[2024 여름방학 React.js 스터디] 이가인 #4주차 (0) | 2024.08.02 |
---|---|
[2024 여름방학 React.js 스터디] 이종윤 #4주차 (0) | 2024.08.02 |
[2024 여름방학 React.js 스터디] 김태일 #4주차 "리액트 입문(2)" (1) | 2024.08.02 |
[2024 여름방학 React.js 스터디] 김민서 #4주차 (0) | 2024.08.02 |
[2024 여름방학 React.js study] 이가인 #3주차 (0) | 2024.07.26 |