작업환경
$ npm install -g create-react-app
$ create-react-app 프로젝트파일명
해당 포스팅은 VScode에서 create-react-app을 통해 만들어진 React 파일에서 작업한 내용입니다.
배열에 항목 추가하기
상태 관리 및 함수 등록은 모두 App.jsx에서 작성하였습니다.
App.jsx
import React, { useState, useRef } from "react";
import CreateUser from "./components/CreateUser";
import UserList from "./components/UserList";
function App() {
const [inputs, setInputs] = useState({
username: "",
email: "",
});
const [users, setUsers] = useState([
{
id: 1,
username: "cocoon",
email: "asd123@gmail.com",
},
{
id: 2,
username: "ultra",
email: "qwe555@example.com",
},
{
id: 3,
username: "hozae",
email: "zxc789@example.com",
},
]);
const { username, email } = inputs;
const nextId = useRef(4);
const onChange = (e) => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value,
});
};
const onCreate = () => {
const user = {
id: nextId.current,
username,
email,
};
setUsers([...users, user]);
// 또는 setUsers(users.concat(user));
setInputs({
username: "",
email: "",
});
nextId.current += 1;
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
></CreateUser>
<UserList users={users}></UserList>
</>
);
}
export default App;
components/UserList.jsx
import React from "react";
function 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;
components/CreateUser.jsx
import React, { useState, useRef } from "react";
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>
);
}
export default CreateUser;
const [inputs, setInputs] = useState({
username: "",
email: "",
});
const [users, setUsers] = useState([
{
id: 1,
username: "cocoon",
email: "asd123@gmail.com",
},
{
id: 2,
username: "ultra",
email: "qwe555@example.com",
},
{
id: 3,
username: "hozae",
email: "zxc789@example.com",
},
]);
useState함수를 사용하여 컴포넌트의 상태를 관리합니다.
const { username, email } = inputs;
const nextId = useRef(4);
inputs의 username과 email을 추출!
그리고 useRef(initialValue) 함수는 .current 프로퍼티로 전달된 인자(initialValue)로 초기화된 변경 가능한 ref 객체를 반환합니다. users 상태의 경우 원소 개수가 3개 있으므로 nextId를 4로 초기화합니다.
const onChange = (e) => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value,
});
};
input에 변화가 생길 때마다 onChange 이벤트가 발생하여 onChange함수가 실행되고, useState의 Setter함수인 setInputs 함수를 통해 inputs의 상태를 업데이트합니다.
const onCreate = () => {
const user = {
id: nextId.current,
username,
email,
};
setUsers([...users, user]);
// 또는 setUsers(users.concat(user));
setInputs({
username: "",
email: "",
});
nextId.current += 1;
};
'등록' 버튼을 클릭 시 onCreate 이벤트가 발생하면서 onCreate 함수를 실행시킵니다.
onCreate 함수는 배열에 원소를 추가하는 함수입니다. 객체와 마찬가지로 배열에 변화를 줄 때도 불변성을 지키기 위해서 기존 배열을 직접 수정하는 push, split, sort 함수를 사용하면 안 되고, 기존 배열을 복사하여 새로운 배열을 만들어서 업데이트를 해주어야 합니다!
spread 연산자를 사용하거나 concat함수를 사용하면 불변성을 지키면서 배열에 새 항목을 추가할 수 있습니다.
배열에 항목 제거하기
삭제 버튼 클릭 시 해당 user 컴포넌트 삭제 구현
- App. 컴포넌트
- onRemove 함수 추가
- UserList 컴포넌트에 props로 onRemove 전달
- User 컴포넌트
- 삭제 버튼을 추가
- props로 받는 부분에 onRemove도 추가
- onClick 이벤트 등록 (onRemove함수로 user.id 전달)
- UserList 컴포넌트
- props로 받는 부분에 onRemove도 추가
- onRemove 이벤트 추가
App.jsx
import React, { useState, useRef } from "react";
import CreateUser from "./components/CreateUser";
import UserList from "./components/UserList";
function App() {
const [inputs, setInputs] = useState({
username: "",
email: "",
});
const [users, setUsers] = useState([
{
id: 1,
username: "cocoon",
email: "asd123@gmail.com",
},
{
id: 2,
username: "ultra",
email: "qwe555@example.com",
},
{
id: 3,
username: "hozae",
email: "zxc789@example.com",
},
]);
const { username, email } = inputs;
const nextId = useRef(4);
const onChange = (e) => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value,
});
};
const onCreate = () => {
const user = {
id: nextId.current,
username,
email,
};
setUsers([...users, user]);
// 또는 setUsers(users.concat(user));
setInputs({
username: "",
email: "",
});
nextId.current += 1;
};
const onRemove = (id) => {
setUsers(users.filter((user) => user.id !== id));
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}
></CreateUser>
<UserList users={users} onRemove={onRemove}></UserList>
</>
);
}
export default App;
components/UserList.jsx
import React from "react";
function User({ user, onRemove }) {
return (
<div>
<b>{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;
const onRemove = (id) => {
setUsers(users.filter((user) => user.id !== id));
};
App.jsx에서 onReamove 함수를 생성하였고, filter함수를 통해서 인자로 받은 id와 일치하는 항목만 제외하고 users를 업데이트하였습니다.
<button onClick={() => { onRemove(user.id);}}>삭제</button>
UserList.jsx에서 삭제 버튼을 만들어 주었고, 삭제 버튼 클릭 시 onRemove함수에 user.id를 전달합니다.
🤔 궁금증
Q.
onClick={() => onRemove(user.id)} 이 코드는 잘 동작하는데
onClick={onRemove(user.id)} 이 코드는 왜 동작하지 않는 건가요?
A.
onClick={onRemove()} 을 해버리면 해당 컴포넌트가 렌더링이 되는 것과 동시에 onRemove함수를 실행시켜버립니다.
그래서 보통 onClick={onRemove}으로 지정해서 ()를 제외하는 방법으로 함수가 즉시 실행되지 않게 하고, 클릭했을 때 실행이 되도록 해주게 됩니다.
그런데 예제와 같이 onRemove의 경우, 해당 함수가 실행될 때 user.id 값도 받아와야 합니다.
이런 경우에 onClick = { onRemove(user.id) }를 해버리면, 해당 컴포넌트가 렌더링 됨과 동시에 이 함수 실행이 되어버려서 콘솔 창에도 오류가 발생하고 해당 컴포넌트도 렌더링 되지 않게 됩니다.
따라서 이런 문제들을 해결하기 위해 onClick에 콜백 함수를 넣어주고, 해당 함수가 실행될 때 user.id를 건네주어 실행시키는 방법으로 처리를 합니다.
배열에 항목 수정하기
User 컴포넌트의 계정명을 클릭했을 때 계정명이 초록색으로, 다시 누르면 검은색으로 바뀌도록 구현
- App. 컴포넌트
- onToggle 함수 추가
- UserList 컴포넌트에 props로 onToggle 전달
- User 컴포넌트
- b 태그 style 추가
- props로 받는 부분에 onToggle 도 추가
- onClick 이벤트 등록 (onToggle 함수로 user.id 전달)
- UserList 컴포넌트
- props로 받는 부분에 onToggle 도 추가
- onToggle 이벤트 추가
App.jsx
import React, { useState, useRef } from "react";
import CreateUser from "./components/CreateUser";
import UserList from "./components/UserList";
function App() {
const [inputs, setInputs] = useState({
username: "",
email: "",
});
const [users, setUsers] = useState([
{
id: 1,
username: "cocoon",
email: "asd123@gmail.com",
active: true,
},
{
id: 2,
username: "ultra",
email: "qwe555@example.com",
active: false,
},
{
id: 3,
username: "hozae",
email: "zxc789@example.com",
active: false,
},
]);
const { username, email } = inputs;
const nextId = useRef(4);
const onChange = (e) => {
const { name, value } = e.target;
setInputs({
...inputs,
[name]: value,
});
};
const onCreate = () => {
const user = {
id: nextId.current,
username,
email,
};
setUsers([...users, user]);
// 또는 setUsers(users.concat(user));
setInputs({
username: "",
email: "",
});
nextId.current += 1;
};
const onRemove = (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}
></CreateUser>
<UserList
users={users}
onRemove={onRemove}
onToggle={onToggle}
></UserList>
</>
);
}
export default App;
components/UserList.jsx
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;
const [users, setUsers] = useState([
{
id: 1,
username: "cocoon",
email: "asd123@gmail.com",
active: true,
},
{
id: 2,
username: "ultra",
email: "qwe555@example.com",
active: false,
},
{
id: 3,
username: "hozae",
email: "zxc789@example.com",
active: false,
},
]);
users 배열 내의 객체 안에 active 속성을 추가합니다.
const onToggle = (id) => {
setUsers(
users.map((user) =>
user.id === id ? { ...user, active: !user.active } : user
)
);
};
onToggle 함수는 id값을 전달받아 해당 id값을 가진 객체의 active 속성을 반전시키는 함수입니다.
onToggle 함수를 UserList 컴포넌트에 props로 전달해줘야 합니다.
<b
style={{
cursor: "pointer",
color: user.active ? "green" : "black",
}}
onClick={() => {
onToggle(user.id);
}}
>
{user.username}
</b>
username을 클릭 시 onToggle함수로 user.id를 전달하고 user.active 값이 업데이트되어 username의 색상이 green 혹은 black으로 표시되게 됩니다.
📚참고
https://react.vlpt.us/basic/13-array-insert.html
'⚛️React' 카테고리의 다른 글
[React] 리액트 Hooks : useMemo() 함수 사용법 (0) | 2022.01.05 |
---|---|
[React] 리액트 Hooks : useEffect() 함수 사용법 (4) | 2022.01.04 |
[React] 리액트 배열 렌더링 하기 (map함수를 통해 반복) (0) | 2021.12.28 |
[React] 리액트 useRef로 특정 DOM 선택하기 (0) | 2021.12.27 |
[React] 리액트 input 상태 관리하기 (+여러 개의 input 상태 관리) (0) | 2021.12.26 |