엄지월드

React 기본 문법 알아보기 본문

Front/React

React 기본 문법 알아보기

킨글 2024. 2. 21. 16:38

JSX 

  • javscript로 변환된다. 
  • html 이랑 비슷하지만, 지켜야 할 규칙이 몇가지 있다. 
  • 꼭 닫혀있는 태그 <div>태그를 열었으면, </div>를 통하여 태그를 닫아줘야 합니다.
    • <input text="text">를 <input text="text" />로 닫아야 한다.
  • 감싸져 있는 엘리먼트
    • 두개 이상의 엘리먼트는 무조건 하나의 엘리먼트로 감싸져 있어야 합니다.
<정상 작동>
import React, { Component } from 'react';


class App extends Component {
  render() {
    return (
      <div>
        <h1>안녕하세요 리액트</h1>
      </div>
    );
  }
}

export default App;

<오류 작동>
import React, { Component } from 'react';


class App extends Component {
  render() {
    return (
      <div>
        <h1>안녕하세요 리액트</h1>
      </div>
	  <div>
        <h1>안녕하세요 리액트</h1>
      </div>
    );
  }
}

export default App;
  • 리액트 16.2에서 만들어진 Fragment를 사용하면 에러 없이 사용 가능하다. 
import React, { Component, Fragment } from 'react';

class App extends Component {
  render() {
    return (
      <Fragment>
        <h1>안녕하세요 리액트</h1>
        <h1>안녕하세요 리액트</h1>
      </Fragment>
    );
  }
}

export default App;
  • JSX 안에 자바스크립트 변수 사용
import React, { Component, Fragment } from 'react';

class App extends Component {
  render() {
    const name = 'gd';
    return <div>hello {name}</div>;
  }
}

export default App;
  • 삼항연산자 사용
import React, { Component, Fragment } from 'react';

class App extends Component {
  render() {
    return <div>{1 + 1 === 3 ? '맞다' : '틀리다!'}</div>;
  }
}

export default App;
  • && 연산자 사용
import React, { Component, Fragment } from 'react';

class App extends Component {
  render() {
    const name = 'gd';
    return <div>{name === 'gd' && <div>지디</div>}</div>;
  }
}

export default App;

 

함수 선언하고 바로 사용하고 싶은 경우

import React, { Component, Fragment } from 'react';

class App extends Component {
  render() {
    const value = 1;
    return (
      <div>
        {(function () { 
          if (value === 1) return <div>1이다!</div>;
          if (value === 2) return <div>2이다!</div>;
          if (value === 3) return <div>3이다!</div>;
          return <div>없다</div>;
        })()}
      </div>
    );
  }
}

export default App;
  • style 적용
import React, { Component } from 'react';

class App extends Component {
  render() {
    const style = {
      backgroundColor: 'black',
      padding: '16px',
      color: 'white',
      fontSize: 15 + 10 + 'px'
    };
    return <div style={style}>Hello, World!</div>;
  }
}

export default App;
  • class 선언 및 CSS 파일로 분리하기 (className으로 선언)
import React, { Component } from 'react';
import './App.css';
class App extends Component {
  render() {
    return <div className="App">Hello, World!</div>;
  }
}

export default App;
  • 주석 사용하는 방법
import React, { Component } from 'react';
import './App.css';
class App extends Component {
  render() {
    return (
      <div
        somthing="somthing" // 중간에 주석 남기는 방법
      >
        {/* 주석을 작성하는 방법 */}
        <h1>리액트</h1>
      </div>
    );
  }
}

export default App;
  • props
    • 부모 컴포넌트가 자식 컴포넌트에 값을 전달할 때에 사용
    • <Child value="value" />인 경우 value가 하나의 props이다. 
[App.js]
import React, { Component } from 'react';
import MyName from './MyName';

class App extends Component {
  render() {
    return <MyName name="리액트" />;
  }
}

export default App;


[MyName.js] 최신 코드 
import React, { Component } from 'react';

class MyName extends Component {
  static defaultProps = {
    // props 기본값 설정하기
    name: '기본이름'
  };

  render() {
    return (
      <div>
        안녕하세요! 제 이름은 <b>{this.props.name}</b>입니다.
      </div>
    );
  }
}

export default MyName;

[MyName.js] 이전 코드
import React, { Component } from 'react';

class MyName extends Component {
  render() {
    return (
      <div>
        안녕하세요! 제 이름은 <b>{this.props.name}</b>입니다.
      </div>
    );
  }
}

MyName.defaultProps = {
  name: '기본이름'
};

export default MyName;
  • 함수형 컴포넌트 
import React, { Component } from 'react';

const MyName = ({ name }) => {
  return <div>안녕하세요! 제 이름은 {name} 입니다.</div>;
};

MyName.defaultProps = {
  name: '기본이름'
};
export default MyName;

 

  • state
    • state는 내부에서 변경 할 수 있다. 
    • 변경할 때는 언제나 setState 라는 함수를 사용한다. 
import React, { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0
  };
  handleIncrease = () => {
    // this.state.number = this.state.number + 1; // 절대로 이렇게 하면 안된다.
    this.setState({
      number: this.state.number + 1
    });
  };
  handleDecrease = () => {
    // arrow안하고 함수로만 선언하면 this가 뭔지 모르게 된다.
    this.setState({
      number: this.state.number - 1
    });
  };

  render() {
    return (
      <div>
        <h1>카운터</h1>
        <div>값: {this.state.number}</div>
        <button onClick={this.handleIncrease}>+</button>
        <button onClick={this.handleDecrease}>-</button>
      </div>
    );
  }
}

export default Counter;
  • state에서 arrow function을 사용하고 싶지 않은 경우, 생성자를 선언해주어야 한다.
import React, { Component } from 'react';

class Counter extends Component {
  state = {
    number: 0
  };
  constructor(props) {
    // arrow안하고 함수로만 선언하면 this가 뭔지 모르게 되기 때문에 선언
    super(props);
    this.handleIncrease = this.handleIncrease.bind(this);
    this.handleDecrease = this.handleDecrease.bind(this);
  }
  handleIncrease() {
    this.setState({
      number: this.state.number + 1
    });
  }
  handleDecrease() {    
    this.setState({
      number: this.state.number - 1
    });
  }

  render() {
    return (
      <div>
        <h1>카운터</h1>
        <div>값: {this.state.number}</div>
        <button onClick={this.handleIncrease}>+</button>
        <button onClick={this.handleDecrease}>-</button>
      </div>
    );
  }
}

export default Counter;
  • LifeCylce API
    • 나타날 때 
    • 업데이트될 때
    • 사라질 때 
    • Mounting
      • 컴포넌트가 브라우저에 나타나는 것 
      • constructor
        • 브라우저에서 가장 먼저 실행되는 함수 
      • getDerivedStateFromProps
        • props로 받은 값을 state로 그대로 동결시키고 싶다. 
        • 마운팅 과정에서도 사용. 
        • props가 바뀔때에도 실행됨 
        • nextProps, prevState 파라미터를 기본적으로 선언해야함 
[App.js]
import React, { Component } from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  state = {
    counter: 1
  };

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };

  render() {
    return (
      <div>
        <MyComponent parentValue={this.state.counter} sss={3} />
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

export default App;

[MyComponent.js]
import React, { Component } from 'react';

class MyComponent extends Component {
  state = {
    childValue: 999
  };

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.parentValue !== nextProps.parentValue) {
      return {
        childValue: nextProps.parentValue
      };
    }
    return null;
  }

  render() {
    return (
      <div>
        <p>props: {this.props.parentValue}</p>
        <p>state: {this.state.childValue}</p>
      </div>
    );
  }
}

export default MyComponent;
  • render
    • 우리가 어떤 dom을 만들게 될지, 어느 값을 전달해줄지를 전달
  • componentDidMound
    • 실제 브라우저에 나타남 
    • 주로 외부 library인 chart, d3 등... 
    • 특정 돔에다가 차트를 그려주세요!라고 코드를 작성할 수 있음
    • api ajax를 요청할 때 주로 여기서 진행 
    • 컴포넌트가 나타나고 몇 초뒤에 뭐를 하고 싶다. 
    • 컴포넌트가 나타나고 특정 dom을 읽고 싶다. 
    • 우리가 만든 컴포넌트가 나타난 이후에 할 작업을 명시!
    • 이벤트 리스닝, API 요청 등..
import React, { Component } from 'react';
import Counter from './Counter';

class App extends Component {
  constructor(props) {
    super(props);
    console.log('constructor call...');
  }
  
  componentDidMount() {
    console.log('componentDidMount call...');
    console.log(this.myDiv.getBoundingClientRect()); // 특정 돔의 실제 크기가 몇인지 확인
  }
  render() {
    return (
      <div ref={(ref) => (this.myDiv = ref)}> // 여기서 넣어주어야 componentDidMount() 부분에서 사용 가능
        <h1>안녕하세요 리액트</h1>
      </div>
    );
  }
}

export default App;

 

  • Updating
    • *sholdComponentUpdate
      • Component가 업데이트 되는 성능을 최적화시키고 싶을 때에 사용 
      • 일반적으로 부모 컴포넌트가 리렌더링되면 자식도 리렌더링됨
        • 하지만 작업이 불필요해질때가 있음. 
        • virtual Dom에 그리는 것조차도 아껴주고 싶다하는 경우 사용. 
      • true나 false 값을 반환가능. false면 render 안되고 멈출 수 있음. 
      • 디폴트 값은 true이다. 
[MyComponent.js]
import React, { Component } from 'react';

class MyComponent extends Component {
  state = {
    childValue: 999
  };

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.parentValue !== nextProps.parentValue) {
      return {
        childValue: nextProps.parentValue
      };
    }
    return null;
  }

  shouldComponentUpdate(nextProps, nextState) { 
    if (nextProps.parentValue === 10) return false; // 10이 되면 1번 실행되지 않음.
    return true;
  }

  render() {
    return (
      <div>
        <p>props: {this.props.parentValue}</p>
        <p>state: {this.state.childValue}</p>
      </div>
    );
  }
}

export default MyComponent;

[App.js]
import React, { Component } from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  state = {
    counter: 1
  };

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };

  render() {
    return (
      <div>
        <MyComponent parentValue={this.state.counter} sss={3} />
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

export default App;

 

  • getSnapshotBeforeUpdate
    • 우리가 렌더링을 한 다음에 렌더링을 한 결과물인 브라우저상에 반영되기 바로 직전에 호출
      • 스크롤의 위치, 해당 돔의 크기를 사전에 가져오고 싶은 경우 
  • componentDidUpdate
    • 작업을 마치고 컴포넌트가 update 되었을 때에 호출되는 함수 
    • 예로 들면 state가 바뀌었을때.
      • 이전의 상태와 지금의 상태가 달라진 경우 처리 가능 
  • Unmounting
    • 컴포넌트가 사라지는 과정에서 호출되는 함수 
    • componentDidMount에서 설정한 리스너를 해제하는 작업을 해주면 된다. 
import React, { Component } from 'react';

class App extends Component {
  constructor(props) {
    super(props);
    console.log('constructor call...');
  }
  componentDidMount() {
    console.log('componentDidMount call...');
    console.log(this.myDiv.getBoundingClientRect()); // 특정 돔의 실제 크기가 몇인지 확인
  }
  render() {
    return (
      <div ref={(ref) => (this.myDiv = ref)}>
        <h1>안녕하세요 리액트</h1>
      </div>
    );
  }
}

export default App;

  • componentWillMount
    • mount가 사라질 때에 발생 
[MyComponent.js]
import React, { Component } from 'react';

class MyComponent extends Component {
  state = {
    childValue: 999
  };

  static getDerivedStateFromProps(nextProps, prevState) {
    if (prevState.parentValue !== nextProps.parentValue) {
      return {
        childValue: nextProps.parentValue
      };
    }
    return null;
  }

  shouldComponentUpdate(nextProps, nextState) {
    if (nextProps.parentValue === 10) return false;
    return true;
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.parentValue !== prevProps.parentValue) {
      console.log('값이 바뀌었다.', this.props.parentValue);
    }
  }

  componentWillUnmount() {
    console.log('Good Bye');
  }

  render() {
    return (
      <div>
        <p>props: {this.props.parentValue}</p>
        <p>state: {this.state.childValue}</p>
      </div>
    );
  }
}

export default MyComponent;

[App.js]
import React, { Component } from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  state = {
    counter: 1
  };

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };

  render() {
    return (
      <div>
        {this.state.counter < 10 && (
          <MyComponent parentValue={this.state.counter} /> // 조건 설정
        )}
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

export default App;
  • 컴포넌트에 에러 발생 
    • render 함수에서 에러가 발생한다면, 리액트 앱이 크래쉬 되어버립니다. 그러한 상황에 유용하게 사용 할 수 있는 API입니다.
    • 에러가 날만한 컴포넌트의 부모 컴포넌트에서 정의
[App.js]
import React, { Component } from 'react';
import MyComponent from './MyComponent';

class App extends Component {
  state = {
    counter: 1,
    error: false
  };

  componentDidCatch(error, info) {
    // 에러가 날만한 컴포넌트의 부모 컴포넌트에서 정의
    this.setState({
      error: true
    });
    console.log(error); // 에러 정보
    console.log(info); // 에러 정보
    // API를 통해서 서버로 오류 내용 날리기
  }

  handleClick = () => {
    this.setState({
      counter: this.state.counter + 1
    });
  };

  render() {
    if (this.state.error) {
      return <div>에러가 났어요 </div>; 
    }
    
    return (
      <div>
        {this.state.counter < 10 && (
          <MyComponent parentValue={this.state.counter} />
        )}
        <button onClick={this.handleClick}>Click Me</button>
      </div>
    );
  }
}

export default App;

 

  • 컴포넌트&데이터 구조 생각해보기
    • 데이터는 단방향으로 흐른다.
    • 아래에서부터 위로 흐르게 된다. 
    • DiaryEditor에서 create하게 되면 setData를 호출하게 되고, DiaryList에서는 해당 List를 보여준다. 

 

  • Lifecycle
    • React 컴포넌트의 생애 주기(생명 주기)
    • 탄생 (Mount)
      • 화면에 나타나는 것
      • 초기화 작업 
    • 변화(Update)
      • 업데이트(리렌더)
      • 예외 처리 작업
    • 죽음(UnMount)
      • 화면에서 사라짐 
      • 메모리 정리 작업
  • 클래스형 컴포넌트
    • Class형 컴포넌트의 길어지는 코드 길이 문제
    • 중복 코드, 가독성 문제 등등 
    • 클래스형 -> 함수형 컴포넌트로 변화함. 
  • useEffect( () => {}, []);
    • 의존성 배열에 있는 값이 변화되면 렌더링이 됨.

 

Unmound를 하려면 콜백함수가 함수를 하나 리턴하게 하면 됩니다. 

그러면 리턴되는 함수는 unmount 시점에 실행됩니다.  

 

  • nextProps가 prevProps와 동일한 값을 가지면 true를 반환하고, 그렇지 않다면 false를 반환 

  • 메모이제이션된 콜백을 반환합니다.

  • useReducer 상태 변화 로직 분리하기

 

Comments