소스코드 : https://github.com/leaveittogod0123/ReactLab

state 내부 배열 처리

state에 참조값 형태의 state의 경우에는 데이터를 수정하지 않고,
새로운 객체나 배열에 값을 복사해 수정하는 방법을 사용해야합니다.

state 값을 수정할때는 this.setState({ })함수를 사용했죠.

배열의 경우는 concat를 사용해요 추가한 새로운 배열을 전달합니다.

this.setState({
    list: this.state.list.concat(newObj);
})

다른 방법으로는 Immutability Helper를 사용하는 방법

또 다른 방법 spread operator를 사용하는 방법

this.state = {
    a: "1",
      b: "2",
      c: {
      d: "3",
      e: "4",
      f: {
        change_this_value : "0",
        this_stays_name: "6"
      }
    }
}

...
this.setState({
  ...this.state,
  c: {
    ...this.state.c,
    f: {
      ...this.state.c.f,
      change_this_value: "5"
    }
  }
})

spread operator는 배열에서 마찬가지로 동작합니다.
추가 삭제

//추가
const array = [1,2,3,4,5];
const newArray = [...array, 7];

console.log(JSON.stringify(newArray, null, 2));

// 삭제
const array = [1,2,3,4,5];
const newArray = [...array.slice(0,2), "수정",...array.slice(3,array.length-1)];

데이터 추가 기능

  • 화면에 html을 이용하여 데이터 입력받을 input을 통해 입력 엘리먼트를 만듭니다.
  • react를 통해 input과 state를 연결하여 state로 input값을 관리합니다.
  • 상위 컴포넌트에서 관리하는 데이터에 값을 추가하기 위해서 하위 컴포넌트로 메서드를 내려보냅니다.

상위 컴포넌트 Contact에 연락처 객체를 state로 관리하고 있습니다.
하위 컴포넌트 ContactCreate를 생성해서 데이터를 입력받아 Contact의 연락처 객체에 값을 추가할 것입니다.

화면에 html을 이용하여 데이터 입력받을 input을 통해 입력 엘리먼트를 만듭니다.

render() {
    return (
      <div>
        <h2>Create Contact</h2>
        <div>
          <input
            type="text"
            name="name"
            placeholder="name"
            value={this.state.name}
            onChange={this.handleChange}
          />
          <input
            type="text"
            name="phone"
            placeholder="phone"
            value={this.state.phone}
            onChange={this.handleChange}
          />
        </div>
        <button type="button" onClick={this.handleClick}>
          Create
        </button>
      </div>
    );
  }

react를 통해 input과 state를 연결하여 state로 input값을 관리합니다.

  constructor(props) {
    super(props);
    this.state = {
      name: "",
      phone: "",
    };
  }

  handleChange = (e) => {
    const nextState = {};
    nextState[e.target.name] = e.target.value;
    this.setState(nextState);
  };

상위 컴포넌트에서 관리하는 데이터에 값을 추가하기 위해서 하위 컴포넌트로 메서드를 내려보냅니다.

그리고 하위컴포넌트에서는 이벤트를 통해 내려온 메서드로 데이터를 추가합니다.

상위 컴포넌트에서 state를 수정할 메서드를 하위컴포넌트로 내려보냄

return (
      <div>
         ...
        <ContactCreate onCreate={this.handleCreate} /> <-
      </div>
    );

하위 컴포넌트에서는 내려받은 메서드를 실행

  handleClick = () => {
    const { name, phone } = this.state;
    const contact = { name, phone }; //Object Property Value Shorthand
    this.props.onCreate(contact);
    this.setState({
      name: "",
      phone: "",
    });
  };

레퍼런스 : Object Property Value Shorthand in JavaScript with ES6 - alligator

데이터 제거 / 수정 기능

  • 가장 먼저 제거, 수정을 위한 인터페이스 생성
  • 제거, 수정하기 위한 state 관리
  • 상위 컴포넌트에서 관리하는 데이터에 값을 추가하기 위해서 하위 컴포넌트로 메서드를 내려보냅니다. <- 이 부분은 데이터 추가와 동일합니다.

가장 먼저 제거, 수정을 위한 인터페이스 생성

render() {
    const details = (
      <div>
        <p>{this.props.contact.name}</p>
        <p>{this.props.contact.phone}</p>
      </div>
    );

    const edit = (
      <div>
        <p>
          <input
            type="text"
            name="name"
            placeholder="name"
            value={this.state.name}
            onChange={this.handleChange}
          />
        </p>
        <p>
          <input
            type="text"
            name="phone"
            placeholder="phone"
            value={this.state.phone}
            onChange={this.handleChange}
          />
        </p>
      </div>
    );

    const view = this.state.isEdit ? edit : details;

    const blank = <div>NotSelected</div>;
    return (
      <div>
        <h1>Selected Contact</h1>
        <div>{this.props.isSelected ? view : blank}</div>
        <button type="button" onClick={this.handleToggle}>
          {this.state.isEdit ? "OK" : "Edit"}
        </button>
        <button type="button" onClick={this.props.onRemove}>
          Remove
        </button>
      </div>
    );
  }

제거, 수정하기 위한 state 관리

constructor(props) {
    super(props);
    this.state = {
      isEdit: false,
      name: "",
      phone: "",
    };
  }

  handleChange = (e) => {
    const nextState = {};
    nextState[e.target.name] = e.target.value;
    this.setState(nextState);
  };

  handleToggle = () => {
    if (!this.state.isEdit) { <- 수정버튼을 클릭시 입력칸에 데이터를 바인딩합니다.
      this.setState({
        name: this.props.contact.name,
        phone: this.props.contact.phone,
      });
    } else {
      this.handleEdit(); <- 수정이 완료되었으면 상위컴포넌트의 값을 수정하는 메서드를 호출합니다.
    }

    this.setState({
      isEdit: !this.state.isEdit,
    });
  };

  handleEdit = () => {
    this.props.onEdit(this.state.name, this.state.phone);
  };

tip

this.setState({})은 비동기입니다.
그래서 isEdit 초기값이 false이면, 버튼을 클릭시에 false가 출력될 것입니다.

console.log(isEdit);
isEdit를 사용하고 싶으시면 !isEdit, 또는 e.target.value를 사용하셔야됩니다.

  handleEdit = () => {
    this.setState({
      isEdit: !this.state.isEdit,
    });
    console.log(isEdit);
  };