TIL 30 | setState 비동기 특성

Soojeong Lee·2021년 7월 11일
0
post-thumbnail

setState 비동기 특성

  • 동기기적, 비동기적 특성은 자바스트립트의 특성이다.
  • 자바스크립트의 이러한 특성 때문에 원하는대로 코드가 동작하지 않는 순간을 마주하게 된다.
  • 혹은 당장은 동작할지 몰라도 추후엔 문제가 발생할 여지가 있다.

✏️ 특히 나는 모든 걸(?) CompoenetDidMount안에 두고 state관리를 하는데, 이런 나쁜 습관을 버리고 state의 변화가 필요한 요소들과 아닌 요소들을 나누어 setState를 관리해야한다.

1. 비동기 프로그램이란?

리액트에서 정상적으로 state를 업데이트 하려면 setState 함수를 사용한다. 하지만 setState의 비동기적 특성 때문에 원치 않는 결과를 가져온다.

✏️ 오늘 내가 구현하려고 했던 checkbox에서도 함수가 실행되었을 때와 이벤트가 실행되었을 때 state 업데이트 내용이 한박자씩 느리게 전달되어 문제가 있었다.

Checkbox 처리 시, 미리 확인할 내용

  1. <input>태그에서는 onChange 속성이 필수이다.

  2. <input>태그의 name 프로퍼티를 활용하여 constructor에 값을 정의해준다.

  3. onChange에 따른 이벤트의 값 중에서 boolean을 활용할 수 있는 값을 찾는다.

    ✏️ 아래와 같이 console.log를 찍으면서 필요한 값이 무엇인가 찾아보았다. console.dir(event)를 활용하니, JavaScript 객체의 모든 속성을 볼 수 있었다.

4.여기서 target이라는 반가운 친구를 만났다.

5.target을 열어보니 checked라는 속성이 있었다. 원래 최초 코드에는 input 태그마다 checked라는 속성을 부여해서 적용했었는데..! 애초에 그럴 필요가 없었던 것이다.


6. checked가 어떤 값을 가지고 있는지 확인하기 위해서 console.log(event.target.checked)를 찍어보았다. 결과값은 checked가 되면 true, 해제가 되면 false값을 갖는다.


7. input 의 속성은 boolean 타입인 것을 알았으니, 이제 각 name에 붙여준 이름을 최초엔 false라고 지정해주고, value가 onChange되었을 때 그 반대의 값을 갖게해라 ! 라는 조건을 넣은 handleCheckBox라는 함수를 만들어 주었다.

  handleCheckBox = event => {
    console.log(event.target.name);
    console.log(event.target.value);
    console.dir(event);
    console.log(event.target.checked);

    this.setState(
      {
        [event.target.name]: !this.state[event.target.name],
      }
    );
  };

✏️ 이때 event.target.name을 그냥 가져오려고 하니 가져와지지가 않아서...검색을 해보았더니 [event.target.name]으로 작성하였더니 값이 잘 전달 되었다.

handleCheckBox = event => {
    console.log(event.target.name);
    console.log(event.target.value);
    console.dir(event);
    console.log(event.target.checked);

    this.setState(
      {
        [event.target.name]: !this.state[event.target.name],
      }
    );
  };

setState 동기처리

이렇게 함수를 만들고 handleCheckBox에서 onChange되었을 때 boolean 값 변화가 있는지 확인을 위해 state값을 찍어보았다....!

  handleCheckBox = event => {
    this.setState(
      {
        [event.target.name]: !this.state[event.target.name],
      }
    );
    console.log(this.state);
  };

checked의 T/F 값이 하나씩 밀려서 나오기 시작했다.. 이런 문제에 대하여 동기, 비동기의 문제일 것이라는 이야기를 들었다...! 출처 이곳에서 도움을 얻어 handleCheckBox에 arrow 함수를 적어 해결하였다.

전체 코드
굴러는 가지만 리팩토링 할게 많다.
1. input태그 정리
2. fetch함수 주소 정리(4개다 체크 후 해제했을 때 ?가 주소에 남는다... 흑..데이터 연결을 해봐야 알겠지만 아마 ? 가 있으면 최초 상태와는 다르게 컴포넌트가 보일거같은 느낌..)

 import React, { Component } from 'react';

// import { GET_PRODUCTS_API } from '../../../src/config.js';

import ProductCard from './ProductCard/ProductCard';

import './Product.scss';

export class Product extends Component {
  constructor() {
    super();
    this.state = {
      productCard: [],
      addCart: false,
      bone: false,
      hair: false,
      growth: false,
      skin: false,
    };
  }

  componentDidMount() {
    // fetch(`${GET_PRODUCTS_API}`)
    fetch('./data/ProductData.json')
      .then(res => res.json())
      .then(data => {
        this.setState({
          productCard: data.message,
        });
      });
  }

  makeCondition = () => {
    let fillter = [];

    if (this.state.bone) {
      fillter.push(`efficacy=1`);
    }

    if (this.state.hair) {
      fillter.push(`efficacy=2`);
    }

    if (this.state.growth) {
      fillter.push(`efficacy=3`);
    }

    if (this.state.skin) {
      fillter.push(`efficacy=4`);
    }

    console.log(test.join('&'));
    console.log(`./data/ProductData.json?${fillter.join('&')}`);
    // fetch(`${GET_PRODUCTS_API}?`)
    fetch(`./data/ProductData.json?${fillter.join('&')}`)
      .then(res => res.json())
      .then(data => {
        this.setState({
          productCard: data.message,
        });
      });
  };

  handleCheckBox = event => {
    console.log(event.target.name);
    console.log(event.target.value);
    console.dir(event);
    console.log(event.target.checked);

    this.setState(
      {
        [event.target.name]: !this.state[event.target.name],
      },
      () => {
        this.makeCondition();
      }
    );
  };

  render() {
    const { productCard } = this.state;

    return (
      <div className="Product">
        <header className="productHeader">
          <h1>
            건강한 삶을 위한
            <br />
            빌리의 연구와 도전은 계속됩니다.
          </h1>
        </header>
        <section className="productBody">
          <h2 className="sr-only">Product Body</h2>

          <form className="productCategory">
            <input type="checkbox" name="bone" onChange={this.handleCheckBox} />
            <label></label>
            <input type="checkbox" name="hair" onChange={this.handleCheckBox} />
            모발
            <input
              type="checkbox"
              name="growth"
              onChange={this.handleCheckBox}
            />
            성장
            <input type="checkbox" name="skin" onChange={this.handleCheckBox} />
            피부
          </form>
        </section>
      </div>
    );
  }
}
export default Product;
profile
🍼 newbie frontend developer

0개의 댓글