[React] 입문 - 2

semi·2021년 2월 3일
0

React

목록 보기
3/4

13. 배열에 항목 추가하기

input 2개와 button 1개로 이루어진 CreateUser.js를 src디렉터리에 생성한다.

import React 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;

상태 관리를 CreateUser에서 하지 않고 부모 컴포넌트 App에서 처리하고, input 값과 이벤트로 등록할 함수를 props로 받아 사용한다.
users도 userState를 사용하여 컴포넌트의 상태로서 관리하도록 한다.

App.js

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';
import './App.css';
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); //초기값을 4로 설정=>.current의 기본값이 된다.
  const onCreate = () => {
    setInputs({//등록 버튼을 눌렀을 때 input 값들을 초기화 시킨다. 입력박스를 빈칸으로 초기화한다.
      username: '',
      email: '',
    });
    nextId.current += 1;
  };
  return (
    <Wrapper>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} />
    </Wrapper>
  );
}
export default App;

이제 배열에 변화를 준다.
배열에 변화를 줄때에는 객체와 똑같이 !!!불변성!!!을 지켜야 한다.
따라서 배열의 push, splice, sort 처럼 기존배열을 바꾸는 함수는 사용하면 안되고 사용하더라도 기존 배열을 복사한 후 사용해야 한다.

불변성을 지키면서 배열에 새 항목을 추가하는 방법은 2가지가 있다.

첫 번째로 spread 연산자를 사용하는 것이다.

 const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    //1. spread 연산자를 사용하여 새 항목 추가
    setUsers([...users, user]);
    setInputs({
      username: '',
      email: '',
    });
    nextId.current += 1;
  };

두 번째로 concat 함수를 사용하는 것이다.
concat 함수는 기존의 배열을 수정하지 않고, 새로운 원소가 추가된 새로운 배열을 만든다.

const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    //2. concat 함수 사용하여 새 항목 추가
    setUsers(users.concat(user));
    setInputs({
      username: '',
      email: '',
    });
    nextId.current += 1; 
  };

14. 배열에 항목 제거하기

UserList에서 각 User 컴포넌트를 보여줄 때 삭제 버튼을 렌더링한다.
배열에 있는 항목을 제거할 때에는 불변성을 지키면서 업데이트를 해야 한다.
이때 filter 내장 함수를 사용하는 것이 가장 편하다.
filter : 배열에서 특정 조건이 만족하는 원소들만 추출하여 새로운 배열을 반환한다.

삭제 버튼을 눌렀을 때 props로 받아온 onRemove 함수의 파라미터로 삭제 버튼이 눌린 객체의 user.id 값을 파라미터로 받는다.
onRemove : id가 ~인 객체를 삭제해라.

UserList.js

import React from 'react';
function User({ user }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}
function UserList({ users }) {
  return (
    <div>
      {users.map((user) => (
        <User user={user} key={user.id} onRemove={onRemove} />
      ))}
    </div>
  );
}
export default UserList;

App.js

import React, { useRef, useState } from 'react';
import Wrapper from './Wrapper';
import UserList from './UserList';
import CreateUser from './CreateUser';
import './App.css';
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 name = 'react';
  const style = {
    backgroundColor: 'black',
    color: 'aqua',
    fontSize: 24,
    padding: '1rem',
  };
  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) => {
    setUsers(users.filter((user) => user.id !== id));
  };
  return (
    <Wrapper>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} onRemove={onRemove} />
    </Wrapper>
  );
}
export default App;

15. 배열 항목 수정하기

User 컴포넌트에 계정명을 클릭했을때 색상이 초록색으로 바뀌고 다시 누르면 검정색으로 바뀌도록 구현한다.

App컴포넌트의 users 배열의 객체에 active 속성을 추가한다.
active 값에 따라 폰트의 색상을 바꿔주도록 한다.
cursor 필드를 설정하여 마우스를 올렸을때 커서가 손가락 모양으로 변하도록 한다.

App.js 부분

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,
    },
  ]);

UserList.js

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;

App.js에 onToggle 함수를 구현한다.
배열의 불변성 유지를하면서 업데이트 할 때 배열 내장 함수인 map 함수를 사용할 수 있다.
onToggle : id 값을 비교해서 id가 다르다면 그대로 두고, 같다면 active 값을 반전시키도록 구현한다.

App.js

  const onToggle = (id) => {
    setUsers(
      users.map((user) => {
        user.id === id ? { ...user, active: !user.active } : user;
      })
    );
  };

오류발생(해결 못함)

line 74:~
: user.id === id ? { ...user, active: !user.active } : user;
책 코드

해결
오류해결참고
해결방법 1. map() 함수를 사용할때 map(()=>{}) 과 같이 {} 중괄호를 사용할때는 내부에 return을 사용해주어야 한다.

const onToggle = (id) => {
    setUsers(
      users.map((user) =>(
        user.id === id ? { ...user, active: !user.active } : user)
      )
    );
  };

해결방법 2. map()이 반환하는 것은 결국 컴포넌트 하나이기 때문에 {}가 아닌 ()소괄호에 요소를 담아 사용한다.

const onToggle = (id) => {
    setUsers(
      users.map((user) => {
        return user.id === id ? { ...user, active: !user.active } : user;
      })
    );
  };

UserList.js

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>
  );
}

16. useEffect를 사용하여 마운트/언마운트/업데이트시 할 작업 설정하기

마운트 : 처음 나타났을 때
언마운트 : 사라질 때
업데이트 : 특정 props가 바뀔 때

마운트/언마운트 관리

0개의 댓글