Iriton's log

누구든지 하는 리액트 7편: 배열 다루기 (1) 생성과 렌더링 본문

Frontend/Study

누구든지 하는 리액트 7편: 배열 다루기 (1) 생성과 렌더링

Iriton 2024. 10. 16. 18:53

참고 자료

 

누구든지 하는 리액트: 초심자를 위한 리액트 핵심 강좌 | VELOPERT.LOG

이 튜토리얼은 리액트를 1도 모르는 사람들을 위해 작성되었습니다. 만약에 여러분이 리액트를 배우고 싶은데, 아직 뭐가 뭔지 잘 모르겠다! 그렇다면 이 튜토리얼을 진행하고 나면 리액트가 무

velopert.com

 

 

React에서는 state의 값을 직접 수정하면 안 된다.

 

불변성 유지 (데이터의 원본이 훼손되는 것을 막는 것) 때문인데 내장 함수(push, splice, unshift, pop) 배열 자체를 직접 수정하면 안 돼서 기존의 배열에 기반하여 새 배열을 만드는 함수(concat, slice, map, filter)를 사용해야 한다.

 

 

데이터 추가

import React, { Component } from "react";
import PhoneForm from "./components/PhoneForm";

class App extends Component {
  id = 2;
  state = {
    information: [
      {
        id: 0,
        name: "김민준",
        phone: "010-0000-0000",
      },
      {
        id: 1,
        name: "홍길동",
        phone: "010-0000-0001",
      },
    ],
  };
  handleCreate = (data) => {
    const { information } = this.state;
    this.setState({
      information: information.concat({ id: this.id++, ...data }),
    });
  };
  render() {
    const { information } = this.state;
    return (
      <div>
        <PhoneForm onCreate={this.handleCreate} />
        {JSON.stringify(information)}
      </div>
    );
  }
}

export default App;
  1. state 정의
    • information 이라는 state 객체를 정의한다.
  2. handleCreate 메서드
    • 새로운 연락처 정보를 추가하는 메서드
    • data는 PhoneForm 컴포넌트로부터 전달된 새 연락처 정보 객체이다.
    • 현재 state를 가져온다.
    • concat 메서드를 사용해 증가한 id와 …data 즉, 그 외 데이터까지 포함한다.
    • 이로 인해 컴포넌트가 다시 렌더링 된다.
  3. 렌더링
    • PhoneForm 컴포넌트를 렌더링 하고 onCreate prop로 handleCreate 메서드를 전달한다. 이로써 PhoneForm에서 새로운 연락처를 생성할 때 이 메서드가 호출되도록 한다.
    • 현재 저장된 information을 JSON 형식의 문자열로 변환하여 화면에 표시한다.
  4. PhoneForm 컴포넌트와 연동
    • onCreate 콜백을 통해 App 컴포넌트로 전달
    • App 컴포넌트는 전달받은 데이터를 handleCreate 메서드를 통해 information 상태에 추가

이제 위 배열을 컴포넌트로 변환하자.

 

 

map 함수

const a = [1,2,3,4,5];

위와 같은 배열이 있다고 가정했을 때 내부 원소들에 2씩 곱하고 싶다면

const a = [1,2,3,4,5];
const b = [];

b.forEach(number => b.push(number * 2));

위와 같은 방식으로 코드를 짤 수도 있지만

const a = [1,2,3,4,5];
const b = a.map(number => number * 2);

map을 사용하면 더 쉽게 해결할 수 있다.

 

 

컴포넌트 만들기

두 개의 컴포넌트를 만들 것이다.

PhoneInfo : 각 전화번호 정보를 보여 주는 컴포넌트

PhoneInfoList : 여러 개의 PhoneInfo 컴포넌트들을 보여 줌.

// file: src/components/PhoneInfo.js
import React, { Component } from 'react';

class PhoneInfo extends Component {
  static defaultProps = {
    info: {
      name: '이름',
      phone: '010-0000-0000',
      id: 0
    }
  }
  
  render() {
    const style = {
      border: '1px solid black',
      padding: '8px',
      margin: '8px'
    };

    const {
      name, phone, id
    } = this.props.info;
    
    return (
      <div style={style}>
        <div><b>{name}</b></div>
        <div>{phone}</div>
      </div>
    );
  }
}

export default PhoneInfo;

defaultProps은 info의 기본값을 설정함으로써 info 값 전달하는 것을 까먹게 된다 해도 crash 되는 것을 방지한다.

// src/components/PhoneInfoList.js
import React, { Component } from 'react';
import PhoneInfo from './PhoneInfo';

class PhoneInfoList extends Component {
  static defaultProps = {
    data: []
  }

  render() {
    const { data } = this.props;
    const list = data.map(
      info => (<PhoneInfo key={info.id} info={info}/>)
    );

    return (
      <div>
        {list}    
      </div>
    );
  }
}

export default PhoneInfoList;

PhoneInfo 컴포넌트를 import 하여 data 라는 배열을 가져와서 map을 통해 JSX로 변환한다. 이 과정에서 key라는 값도 추가됐다. 이 key는 React에서 배열을 렌더링할 때 꼭 필요한 값이다.

현재는 id로 key를 사용하고 있는데, 데이터베이스에 데이터를 추가하게 된다면 고유 id를 사용하게 될 것이다.

key를 사용하는 이유는 데이터를 추가할 때마다 고정적인 고유 값을 부여해 줌으로써 React가 변화를 감지해내고 업데이트를 하게 될 때 조금 더 똑똑하게 처리할 수 있게 되기 때문이다.

 

// file: src/App.js
import React, { Component } from 'react';
import PhoneForm from './components/PhoneForm';
import PhoneInfoList from './components/PhoneInfoList';

class App extends Component {
  id = 2
  state = {
    information: [
      {
        id: 0,
        name: '김민준',
        phone: '010-0000-0000'
      },
      {
        id: 1,
        name: '홍길동',
        phone: '010-0000-0001'
      }
    ]
  }
  handleCreate = (data) => {
    const { information } = this.state;
    this.setState({
      information: information.concat({ id: this.id++, ...data })
    })
  }
  render() {
    return (
      <div>
        <PhoneForm
          onCreate={this.handleCreate}
        />
        <PhoneInfoList data={this.state.information}/>
      </div>
    );
  }
}

export default App;

 

 

Comments