리액트-3

🔗강의자료:웹 게임을 만들며 배우는 리액트

import와 require 비교

  • importrequire는 패키지를 불러오는 방법이다.

  • es2015 = 바벨이 지원하는 것으로 import
    export default NumberBaseball; // import NumberBaseball;
    디폴트는 한번만 쓸 수 있고
    export const hello = 'hello'; //import { hello }
    변수명만 안겹치면 많이 쓸 수 있고 한번에 여러개 가져올 수 있음

  • common js
    const React = require('react');
    exports.hello = 'hello';
    module.exports = NumberBaseball;

  • exports 되는게 객체나 배열이면 구조분해 가능
    {} 이 부분이 구조분해 문법

  • 노드 모듈 시스템에서 module.exports = {hello: 'a'};
    exports.hello = 'a'는 같다.

  • import React, { Component } from 'react'; 하나로 묶을 수 있음

  • 중괄호로 된 것은 default로 export한게 아니라 변수나 값같은걸로 export 가능

  • 이렇게 변환 가능

//import React from 'react';
//import Reactdom from 'react-dom';
//import { hot } from 'react-hot-loader/root';
//import NumberBaseball from './NumberBaseball.jsx';

https://www.daleseo.com/js-module-require/


오류 발생

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

이런 오류가 발생해서 수업과 달리 나는 require를 사용해서 틀린 줄 알고 다시 코드를 import로 작성함 (물론 적으면서도 둘 다 되지 않나? 라는 의문은 있었음)

📝NumberBaseball.jsx

import React, { Component } from 'react';
...
export default NumberBaseball;

📝Client.jsx

import React from 'react';
import ReactDom from 'react-dom';

import NumberBaseball from './NumberBaseball');

ReactDom.render(<NumberBaseball />, document.querySelector('#root'));

로 고치니까 됨. 보니까 require에서도 <NumberBaseball /> 부분에 .jsx파일까지 적었길래 안되던거였음
그래서 require로 바꿔서 해보니까 다시 다른 이슈가 뜸

React.createElement is not a function

이번엔 이런 에러가 뜸👶

리액트 반복문(map)

  • valueonChange는 같이 꼭 같이 써야함!
    -> defaultValue로 한번에도 가능

  • 💖반복문 map
    : 반복하는 부분을 배열로 만들어서 map함수로 씀

📝입력

<ul>
  {['사과','배','딸기','수박','바나나','귤','포도','감','밤'].map((v) => {
    return(
      <li>{v}</li>
    );
  })}
</ul>

🎨결과

리액트 반복문(key)

간단한 배열이 아니라 태그들이 들어가있는 반복문을 만들어야 한다면

  • 2차 배열 반복문
    : 출력 받는 부분을 배열로 정확하게 나타내 주면 됨

📝입력

<ul>
  {[
    ['사과','맛있다'],
    ['배','맛없다'],
    ['딸기','달다'],
    ['수박','시원하다'],
    ['바나나','싫다'],
    ['귤','먹고싶다'],
    ['포도','귀찮다'],
    ['감','떫다'],
    ['밤','좋다']
  ].map((v) => {
    return(
      <li><b>{v[0]}</b> - {v[1]}</li>
    );
  })}
</ul>

🎨결과

  • 리액트가 key를 보고 같은 컴포넌트인지 아닌지 판단
    • 태그에 꼭 key를 넣어줘야함.
      • 👉안 넣으면 오류발생함
    • 고유한 값으로 꼭 만들어야함(key={v.key1+key2})
<ul>
  {[
    {fruit:'사과', taste: '맛있다'},
    {fruit:'배', taste: '맛없다'},
    {fruit:'딸기',taste: '달다'},
    {fruit: '수박',taste: '시원하다'},
    {fruit: '바나나',taste:'싫다'},
    {fruit: '귤',taste: '먹고싶다'},
    {fruit: '포도',taste: '귀찮다'},
    {fruit: '감',taste: '떫다'},
    {fruit: '밤',taste: '좋다'},
    {fruit: '사과',taste: '좋다'}
  ].map((v) => {
    return(
      <li key={v.fruit + v.taste}><b>{v.fruit}</b> - {v.taste}</li>
    );
  })}
</ul>
  • =>게 있고 중괄호대신 소괄호나 생략하면 return없이 return할 수 있음

  • .map(v,i)라고 하고 i를 내면 i는 배열 순서를 말함.

  • key에 i를 쓰면 안됨 : key역할이 성능 최적화인데 i를 쓰면 기능을 못함.
    👉 리액트에서 key를 보고 판단을 하는데 배열순서가 바뀌면 문제가 발생함.

컴포넌트 분리와 props

  • 컴포넌트 분리하는 이유
    • 가독성을 좋게 하기위해
    • 성능최적화 (코드가 길어지만 이렇게 사용)
  • props를 이용해서 컴포넌트에 값 전달
    • 컴포넌트 분리를 하고 import로 코드파일을 불러옴.

📝 NumberBaseball.jsx

<ul>
  {this.fruits.map((v, i) => {
    return(
      <Try value={v} index={i} />
    );
  })}
</ul>

📝 Try.jsx

<li>
  <b>{this.props.value.fruit}</b> - {this.props.index.fruit}
  <div>컨텐츠</div>
  <div>컨텐츠1</div> 
  <div>컨텐츠2</div> 
  <div>컨텐츠3</div>  
</li>

v,i 를 받아줄 수 없기 때문에 props를 사용해서 try.jsx와 연결시켜줌

주석과 메서드 바인딩

map문에 key설정해주기

<Try key={v.fruit + v.taste} value={v} index={i} />

jsx 주석

  • {/* ... */}

메서드 바인딩

  • 사용자 정의 함수에서 () => {} 대신 () {} 이렇게 쓰면 this를 못쓰고 error가 나타남

숫자야구 만들기

  • 리액트에서 push안됨.
    - 리액트가 뭐가 바뀌었는지 확인을 못함

    • const array2 = [...array,2] 기존 array를 복사하고 2를 저장
  • this 반복되어서 보기싫으면 함수밖에
    const {value, tries, answer} = this.state;
    비구조화 할당으로 간단하게 할 수 있다.

숫자야구 hooks로 바꾸기

  • 이전 값 prevTries
  • this 없애기

React Devtools

  • props를 사용하다보면 문제가 많이 발생함

  • NumberBaseball이 부모 Try.jsx가 자녀로 props로 연결되어있음

  • 디버깅하기 좋은 확장 프로그램
    🎨결과

  • 배포 모드에서는 소스 코드및 최적화가 되어있음.

shouldComponentUpdate

  • 성능 개선을 위해 사용

  • 렌더가 되는 상황은 state나 props가 바뀌었을 때임.

    • 하이라이트 업데이트 : 렌더가 될 때마다 반짝거림
    • value가 바뀌는데 tries랑 시도에서 렌더링 되고있음 <- 성능에 문제가 있음
  • 예시에서 onClick에 setState를 호출하니까 count가 바뀌든 말든 rendering이 다시 일어남.
    - 이때 shouldComponentUpdate를 설정해줘야함.

    • 현재 counter와 미래 counter가 다르면 렌더링을 해주고, 같으면 렌더링 x
shouldComponentUpdate(nextProps, nextState, nextContext){
  if (this.state.counter !== nextState.counter){
    return true;
  }
  return false;
}

👉렌더링이 다시 일어나지 않음.

PureComponent와 React.memo

PureComponent

  • PureComponent로 바꾸면 shouldComponentUpdate하는 것과 같음
  • ex) array를 array로 바꾸면 새로운 배열로 해서 바뀌었구나 알아차리는데
const array = this.state.array;
this.state.array.push(1);
this.setState({
array: array,
});
👉 이렇게 array이랑 바꾼 array가 같다고 해버리면 
	PureComponent가 바뀐걸 파악하지못함 
  • 새로운 array를 만들고 싶다면 array: [...this.state.array, 1]이렇게 해줘야함
    👉 렌더링 됨을 확인 가능

  • 가능하면 객체 쓰지말고

  • NumberBaseball 성능 최적화

React.memo

  • 훅스에서 사용하는 방식
  • memo는 컴포넌스를 감싸주면됨.

자식들이 PureComponent나 memo면 부모 코드에도 맞춰서 해줌.

React.createRef

  • 포커스 줄 때
    • class에서는
    1. render 부분에서 focus를 주고싶은 부분에
      onInput = (c) => {this.inputRef = c;}; 해주거나
    2. 따로 함수를 만들어서
      inputRef;
      onInputRef = (c) => {this.inputRef = c;}; //함수만들고
      //포커스가 필요한 부분에
      this.inputRef.focus();
    • hooks에서는
    1. Ref를 useRef로 만듬
      import React, { useState, memo } from 'react'
      const inputRef = useRef(null);
      2.코드 작성 안에 inputRef.current.focus(); 추가
  • class에서 hooks와 비슷하게 inputRef해주기
    1. import React,{Component, createRef }from 'react';
    1. inputRef = createRef(); 불러오기
    2. onInputRef 함수같은거 필요없고 렌더할 때 input태그 속성에 ref={this.inputRef } 추가
    3. 코드 안 focus에서도 this.inputRef.current.focus();로 추가
  • 쉬운방법이 있는데 함수로 ref를 정하는 이유
    : 더 디테일한 내용을 넣을 수 있음

props와 state 연결하기

  • render안에서는 setState하면 안됨.
    👉 무한 반복되기 때문
  • props는 부모가 바꿔야함. 자녀가 바꿀 수는 없음.
    👉 바꿔야할 경우가 생긴다면 props를 state에 넣어서 바꿔줌.

📝Try.jsx(hooks)

import React, {PureComponenet, memo, useState} from 'react';

const Try = memo(({tryInfo}) => {
  const [result, setResult] = useState(tryInfo.result);
  const onClick = () =>{
    setResult('1');
  };
  
  return(
    <li>
      <div>{tryInfo.try}</div>
      <div>{onClick}</div>
    </li>
  )
}
  • 부모로 받은 props를 state로 바로 받을 수 있음.

📝Try.jsx(class)

import React, {PureComponenet, memo, useState} from 'react';

class Try extends PureComponet {
  state = {
    result : this.props.result,
    try: this.props.try,
  };
  render() {
    const {tryInfo} = this.props;
    return (
      <li>
        <div>{this.props.tryInfo.try}</div>
        <div>{this.props.tryInfo.result}</div>
      </li>
    )
  }
}
  • constructor(ref함수 setState함수)가 쓰이는 경우
    👉super랑 constructor는 짝
    • 미세한 컨트롤이 가능해짐
    • 기본 객체로는 안되는 동작들이 있을 때 사용
  • context는 props의 진화형으로 거쳐가는 프록스없이 바로 가는

좋은 웹페이지 즐겨찾기