<아래의 배열 랜더링하기>
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' } ];
<랜더링 1>
import React from 'react'; function 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> <div> <b>{users[0].username}</b> <span>({users[0].email})</span> </div> <div> <b>{users[1].username}</b> <span>({users[1].email})</span> </div> <div> <b>{users[2].username}</b> <span>({users[1].email})</span> </div> </div> ); } export default UserList;
<랜더링 1-1 컴포넌트 재활용>
import React from 'react'; function User({ user }) { return ( <div> <b>{user.username}</b> <span>({user.email})</span> </div> ); } function 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> <User user={users[0]} /> <User user={users[1]} /> <User user={users[2]} /> </div> ); } export default UserList;
배열의 인덱스를 하나하나 조회해가면서 랜더링, 이러한 랜더링은 동적인 배열을 랜더링 하지 못한다.
동적인 배열을 랜더링하기 위해서는 자바스크립트 배열의 내장함수 map()을 사용한다.
- map() 함수는 배열안에 있는 각 원소를 변환하여 새로운 배열을 만들어줌
- map() 함수를 사용하여 일반 데이터 배열 -> 리액트 엘리먼트로 이루어진 배열로 변환
import React from 'react'; function User({ user }) { return ( <div> <b>{user.username}</b> <span>({user.email})</span> </div> ); } function 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;
하지만 console 창을 살펴보면 이러한 에러가 찍혀있다
리액트에서 배열을 랜더링할때에는 key라는 props를 설정해야한다.
-> 배열이 업데이트 될 때 효율적으로 렌더링 할 수 있기 때문이다.
수정되지 않은 기존의 값은 그대로 두고 원하는 곳에 내용을 삽입하거나 삭제한다.
Map에 key값이 없다면 중간의 값이 바뀌었을 때 그 하위 값들이 전부 변하게 된다.
<배열 안에 있는 고유값 id를 key값으로 설정함>
return ( <div> {users.map(user =>( <User user = {user} key={user.id}/> ))} </div> );
<배열 안에 고유 값이 없다면 map() 함수를 사용할때 설정하는 콜백함수의 두번째 파라미터 index를 key값으로 사용한다>
return ( <div> {users.map((user, index) =>( <User user = {user} key={index} /> ))} </div> );
배열에 변화를 줄때에는 객체와 마찬가지로 불변성을 지켜주어야한다. 그렇기 때문에 배열의 push, splice, sort 등의 함수를 사용하면 안된다. 만약에 사용하게 된다면 기존의 배열을 한번 복사하고 나서 사용해야한다.
const nextId = useRef(4); const onCreate = () => { const user = { id: nextId.current, username, email }; setUsers([...users, user]); setInputs({ username: '', email: '' }); nextId.current += 1; };
<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' }, { 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 nextId = useRef(4); const onCreate = () => { const user = { id: nextId.current, username, email }; setUsers(users.concat(user)); setInputs({ username: '', email: '' }); nextId.current += 1; };
<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' }, { 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;
부모컴포넌트에서 state값(input 등등)과 함수를 작성하고 자식 컴포넌트에게 전달하는 구조를 기억하기
불변성을 지키면서 특정원소를 배열에서 제거하기 위해 filter 배열 내장함수 사용한다
- filter를 사용하여 false 인 값만 담는다
- 태그에서 변수를 전달하고 싶을땐 아래와 같이 작성한다
const onRemove = id => { // user.id 가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬 // = user.id 가 id 인 것을 제거함 setUsers(users.filter(user => user.id !== id)); };
<br> <App.js> 전체코드 >```react 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.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;