🚫 배열에 값을 추가할때, 기존 배열에 push로 값을 추가하면 안된다!
💯 기존 배열에 영향을 주지않게끔 새로운 배열을 만들어주고 그 배열에 변화를 주도록 해야한다.
//CreateUser.js
import React from 'react';
// 필요한 컴포넌트를 props 로 받아올 예정
// onchange : input 값이 바뀌게 될 때 호출하는 함수
// onCreate : 버튼을 눌렀을 때 항목을 추가해주는 함수
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;
//App.js
import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
function App() {
// inputs라는 변수에 대해서
// 초기값 {username:'', email:''},
// 변경 함수는 setInputs
const [inputs, setInputs] = useState({
username:'',
email:'',
});
// inputs의 변수를 미리 빼오기
const {username, email} = inputs;
// 기존 객체에 영향이 없도록 Spread를 이용
const onChange = e => {
const {name,value} = e.target;
setInputs({
...inputs,
[name] : value
});
};
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}/>
<UserList users={users}/>
</>
);
}
//App.js
const [users, setUsers]= useState([
{
id: 1,
username: 'doyeon',
email: 'uoayop@kakao.com'
},
{
id: 2,
username: 'woong',
email: 'woong@mungmung.com'
},
{
id: 3,
username: 'woody',
email: 'andy@friend.com'
}
]);
const onCreate = () => {
const user = {
id: nextId.current,
username,
email,
// username, email 대신 ...users 가능
};
// 새로운 객체 user를 만들어서 값 할당
// 기존의 배열 user는 건들이지 않고, user가 추가됨
// 기존 배열 users에 새로 만든 객체 user을 붙여줌
setUsers(users.concat(user));
setInputs({
username:'',
email:''
});
console.log(nextId.current); //4
nextId.current += 1;
}
기존 객체 users
에 새로운 객체 user
를 더해줄 때
spread 사용
setUsers([...users, user]);
concat 사용
setUsers(users.concat(user));
버튼을 눌렀을 때, 유저가 삭제되게 하려고 한다.
이 때, 주의할 점은 삭제 함수를 지정해줄 때 반드시 화살표 함수로 지정해줘야 한다!
- 🚫 만약 그냥 deleteFunc() 이렇게 지정해주면 렌더링과 동시에 요소가 삭제되어 버린다.
💯 함수를 호출하는 것이 아니라 함수를 넣어줘야 한다!
//UserList.js
import React from 'react';
import './App.css';
function User({user, onRemove}){
const {username, email, id } = user;
return(
<div>
<b>{username}</b>
<span>({email})</span>
// 🔥 반드시 화살표 함수로 함수 넣어주기!!!!
<button onClick={() => onRemove(id)}>삭제</button>
</div>
);
}
function UserList({users, onRemove}){
return (
<div>
{
users.map(
(user,index) => (
<User
user={user}
key={user.id}
onRemove={onRemove}
/>
)
)
}
</div>
)
}
export default UserList;
//App.js
const onRemove = id => {
// user.id가 파라미터로 받은 id가 아닌 경우에만
// 새 리스트로 묶어서 반환해준다.
// 반환된 리스트를 setUsers로 업데이트 해준다.
setUsers(users.filter(user => user.id !== id))
}
return (
<>
<CreateUser
username={username}
email={email}
onChange={onChange}
onCreate={onCreate}/>
<UserList users={users} onRemove={onRemove}/>
</>
);
}
map 함수를 사용하면, 쉽게 배열의 요소를 수정할 수 있다.
const onToggle = id => {
setUsers(users.map(
user => user.id === id?
{ ...user, active: !user.active}
: user
))
}
매개변수로 받은 id를 갖는 user를 찾아서
active 변수의 상태를 토글해준다.
이 때, 위의 경우와 마찬가지로 기존의 user 요소를 그대로 들고오고 ...user
,
바뀐 값만 덮어씌워주는 형태로 수정해준다.
정리
배열의 특정 값을 수정할 땐, 기존의 배열에 영향이 가지 않도록, spread를 사용한다.
setState([...기존 배열, 새로 추가된 내용])
배열 각각의 요소에 접근할 땐 map 함수를 사용하면 편하다.
map 함수
map 함수엔 아이템의 고유값을 key 값으로 함께 넣어주는 것이 권장된다.users.map( (user,index) => (<User user={user} key={index} />), )
key 값이 있어야만 렌더링 한 결과물이 어떤 객체를 가리키고 있는지 정확하게 알게된다.
그래야만 조금 더 빠르고 효율적으로 동작하게 된다.