반응형

작업환경

$ 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

https://react.vlpt.us/basic/14-array-remove.html

https://react.vlpt.us/basic/15-array-modify.html

반응형

+ Recent posts