Front-End

vsoghlv@naver.com

React.js 배열 항목 추가, 제거, 수정

배열 항목 추가

먼저 항목을 추가하기 위한 인풋과 버튼을 만들어 App.js 에서 불러온다.

//CreateUser.js
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;

///App.js
import React, { useRef,useState } from "react";
import CreateUser from "./CreateUser";
import UserList from "./UserList";

function App() {
  const users = [
    {
      id: 1,
      username: "Sun",
      email: "123@naver.com",
    },
    {
      id: 2,
      username: "Jung",
      email: "456@naver.com",
    },
    {
      id: 3,
      username: "Kim",
      email: "789@naver.com",
    },
  ];

  const nextId = useRef(4);

  return (
    <>
      <CreateUser></CreateUser>
      <UserList users={users}></UserList>
    </>
  );
}

export default App;

그리고 App.js 에서 CreateUser 에 필요한 props 들을 만들어서 넣어주고 users 의 배열이 컴포넌트의 상태로서 관리할 수 있도록 useState 로 감싸준다.

 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: "Sun",
    email: "123@naver.com",
  },
  {
    id: 2,
    username: "Jung",
    email: "456@naver.com",
  },
  {
    id: 3,
    username: "Kim",
    email: "789@naver.com",
  },
]);

const onCreate = () => {
  setInputs({
    username: "",
    email: "",
  });
  console.log(nextId.current); //4
  nextId.current += 1;
};

////

<CreateUser
  username={username}
  email={email}
  onChange={onChange}
  onCreate={onCreate}
></CreateUser>  

배열도 객체를 수정할때와 마찬가지로 배열을 복사한 후 값을 덮어씌우는 방식으로 해야한다. sort, splice, push 등은 사용해서는 안되는데 만약 sort, splice, push 등을 반드시 사용해야 한다면 배열을 복사한 후 사용해야한다. 배열의 불변성을 지키면서 항목을 추가하는 spread 연산자를 이용하는 방법과 concat 함수를 이용하는 방법등이 있다. 두 방법다 기존의 배열은 건드리지 않는다는 점에서 동일하다.

///App.js
 const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    //spread 연산자 이용시
    setUsers([...users, user]);
    //concat 함수 이용시
    setUsers(users.concat(user));

    setInputs({
      username: "",
      email: "",
    });
    console.log(nextId.current); //4
    nextId.current += 1;
  };

이제 인풋에 이메일과 이름을 쓰고 등록버튼을 누르면 추가가 가능해진다.

배열 항목 제거

먼저 App.js 에서 삭제 시키는 함수를 만들어 UserList 의 porps 로 넣어준다. 배열에서 특정 요소를 삭제할 때도 불변성을 지켜가며 해야 하는데 이때 filter 를 사용하면 편하다. 쉽게 말해 splice 와 같이 해당 요소를 제거 한다기보다는 filter 로 조건을 주고 걸러내어 새로 배열을 만들어내는 느낌이다.

  const onRemove = (id) => {
    setUsers(users.filter((users) => users.id !== id));
  };

위와 같이 setUsers 에서 filter 를 사용해 users 안의 요소들중 id 값이 파라미터로 받은 id 값과 다른 것만 남기고 다시 배열을 재구성시킨다.

이제 UserList 컴포넌트를 확인해보자. UserList.js 에서는 각 div 마다 click 이벤트에 onRemove 함수가 들어간 버튼을 만들어 주고, 그 버튼에 id 값을 보내주면 된다.

function User({ user, onRemove }) {
  return (
    <div>
      <b>
        {user.username} <span>({user.email})</span>
      </b>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}
function UserList({ users, onRemove }) {
  return (
    <div>
      {users.map((user) => (
        <User key={user.id} user={user} onRemove={onRemove}></User>
      ))}
    </div>
  );
}

버튼에 click 이벤트를 넣을 때 주의해야할 점이 있는데, 만약 위와 같이 onClick 시 함수를 만들어 함수 내부에서 onRemove 함수를 호출하지 않고 <button onClick={onRemove(user.id)}> 이런 식으로 onRemove 를 바로 호출한다면 클릭이 아닌 렌더링 됨과 동시에 함수가 호출되어 버린다.

배열 항목 수정

이번에는 클릭하면 색상이 바뀌도록 만들어 보려한다. 먼저 배열안의 객체에 active 라는 boolean 값을 주고 그 값에 따라 색상을 지정해준다.

///App.js
{
  id: 1,
  username: "Sun",
  email: "123@naver.com",
  active: true,
},

//IserList.js User 컴포넌트
<b
  style=
  onClick={() => onToggle(user.id)}
>

위에서 보면 b 에 클릭이벤트로 onToggle 이 있는데 onToggle 함수로 active 값을 변경되게 해줬다.

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

이때 배열안의 특정 요소만 변경할때도 map 함수를 쓸 수 있다. 위의 함수를 풀이해보자면 user.id 가 파라미터로 받은 id 와 같을 때, 즉 클릭한 요소일때, user.active 의 값을 바꿔주고 아닌 경우는 그대로 유지하는 함수이다. 이때도 불변성을 지키기 위해 spread 함수를 이용해 먼저 복사한 후 값을 변경해주어야 한다.

//App.js
import React, { useRef, useState } from "react";
import CreateUser from "./CreateUser";
import UserList from "./UserList";

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: "Sun",
      email: "123@naver.com",
      active: true,
    },
    {
      id: 2,
      username: "Jung",
      email: "456@naver.com",
      active: false,
    },
    {
      id: 3,
      username: "Kim",
      email: "789@naver.com",
      active: false,
    },
  ]);

  const nextId = useRef(4);

  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email,
    };
    setUsers(users.concat(user));
    setInputs({
      username: "",
      email: "",
    });
    console.log(nextId.current); //4
    nextId.current += 1;
  };

  const onRemove = (id) => {
    setUsers(users.filter((users) => users.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;


//UserList.js
import React from "react";

function User({ user, onRemove, onToggle }) {
  return (
    <div>
      <b
        style=
        onClick={() => onToggle(user.id)}
      >
        {user.username} <span>({user.email})</span>
      </b>
      <button onClick={() => onRemove(user.id)}>삭제</button>
    </div>
  );
}
function UserList({ users, onRemove, onToggle }) {
  return (
    <div>
      {users.map((user) => (
        <User
          key={user.id}
          user={user}
          onRemove={onRemove}
          onToggle={onToggle}
        ></User>
      ))}
    </div>
  );
}

export default UserList;