React Advanced

Seulyi Yoo·2022년 7월 13일
0

React

목록 보기
12/12
post-thumbnail

Optimizing Performance

필요할 때만 Render 한다.

Reconciliation

  • Render 전후의 일치 여부를 판단하는 규칙
  • 서로 다른 타입의 두 Element 는 서로 다른 트리를 만들어낸다.
  • 개발자가 key prop 을 통해, 여러 Rendering 사이에서 어떤 자식 Element 가 변경되지 않아야 할 지 표시해 줄수 있다.
// App.js

import logo from './logo.svg';
import './App.css';
import React from 'react';

class Foo extends React.Component {

  componentDidMount() {
    console.log("Foo componentDidMount");
  }

  componentWillUnmount() {
    console.log("Foo componentWillUnmount");
  }

  static getDerivedStateFromProps(nextProps, prevProps) {
    console.log("Foo getDrivedStateFromProps", nextProps, prevProps);
    return {};
  }

  render(){
    console.log("Foo render");
    return (
      <p>Foo</p>
    );
  }
}

class App extends React.Component {

  state = {
    count: 0
  };

  componentDidMount() {
    setInterval(() => {
      this.setState({count: this.state.count + 1});
    }, 1000);
  }

  render() {
    if(this.state.count % 2 === 0) {
      return (
        // <div className='before' title='stuff' />
        // <div style={{color: 'red', fontWeight: 'bold'}} />
        <Foo name="Mark" />
      );
    }

    return (
      // <div className='after' title='stuff' />
      // <div style={{color: 'green', fontWeight: 'bold'}} />
      <Foo name= "Jane" />
    );
  }
}

export default App;
// App.js
// key props

import logo from './logo.svg';
import './App.css';
import React from 'react';

class Foo extends React.Component {

  componentDidMount() {
    console.log("Foo componentDidMount", this.props.children);
  }

  componentWillUnmount() {
    console.log("Foo componentWillUnmount");
  }

  static getDerivedStateFromProps(nextProps, prevProps) {
    console.log("Foo getDrivedStateFromProps", nextProps, prevProps);
    return {};
  }

  render(){
    console.log("Foo render", this.props.children);
    return (
      <p>Foo</p>
    );
  }
}

class App extends React.Component {

  state = {
    count: 0
  };

  componentDidMount() {
    setInterval(() => {
      this.setState({count: this.state.count + 1});
    }, 1000);
  }

  render() {
    if(this.state.count % 2 === 0) {
      return (
        <ul>
          {/* <Foo>First</Foo>
          <Foo>Second</Foo> */}
          <Foo key="2">Second</Foo>
          <Foo key="3">Third</Foo>
        </ul>
      );
    }

    return (
      <ul>
        <Foo key="1">First</Foo>
        <Foo key="2">Second</Foo>
        <Foo ket="3">Third</Foo>
      </ul>
    );
  }
}

export default App;
// App.js
// shouldComponentUpdate
// PureComponent

import logo from './logo.svg';
import './App.css';
import React from 'react';

class Person extends React.Component.PureComponent {

  // PureComponent 도 바뀐 부분이 없으면 렌더하지 않음!

  // 바뀐 부분이 없으면 렌더하지 않는다!
  // shouldComponentUpdate(previousProps){
  //   for(const key in this.props){
  //     if(previousProps[key] !== this.props[key]){
  //       return true;
  //     }
  //     return false;
  //   }
  // }

  render(){
    console.log("Person render");
    const {name, age} = this.props
    return (
      <div>
        {name} / {age}
      </div>
    );
  }
}

class App extends React.Component {

  state = {
    text: "",
    persons: [
      {id: 1, name: "Mark", age: 39},
      {id: 2, name: "Jane", age: 28}
    ]
  };

  render() {
    const { text, persons } = this.state;
    return (
      <div>
        <input type= "text" value={text} onChange={this._change} />
        <ul>{persons.map(person => {
          return <Person {...person} key={person.id} />
        })}</ul>
      </div>    
    );
  }

  _change = e => {
    this.setState({
      ...this.state,
      text: e.target.value
    });
  }
}

export default App;
// App.js

// function 으로 사용할 때, React.memo 를 사용하면 바뀐 부분이 없으면 랜더하지 않음
const Person = React.memo(({name, age}) => {
  console.log("Person render");
  return (
    <div>
      {name} / {age}
    </div>
  );
});
// App.js
// React.memo
// useCallback

import logo from './logo.svg';
import './App.css';
import React, { useState } from 'react';

// function 으로 사용할 때, React.memo 를 사용하면 바뀐 부분이 없으면 랜더하지 않음
const Person = React.memo(({name, age}) => {
  console.log("Person render");
  return (
    <div>
      {name} / {age}
    </div>
  );
});

function App() {

  const [state, setState] = useState({
      text: "",
      persons: [
        {id: 1, name: "Mark", age: 39},
        {id: 2, name: "Jane", age: 28}
      ]
  });

  const toPersonClick = React.useCallback(() => {}, []);

  const { text, persons } = state;
    return (
      <div>
        <input type= "text" value={text} onChange={change} />
        <ul>
          {persons.map(person => {
            return <Person {...person} key={person.id} onClick={toPersonClick} />
          })}
        </ul>
      </div>    
    );
  };

  function change(e) {
    setState({
      ...state,
      text: e.target.value
    });
  };

export default App;

createPortal

Portals

부모 Component 의 DOM 계층 구조 바깥에 있는 DOM 노드로 자식을 Rendering 하는 최고의 방법을 제공함

<!-- public/index.html -->

<div id="modal"></div>
/* src/index.css */

#modal {
  position: absolute;
  top: 0;
  left: 0;
}
// src/components/Modal.jsx

import ReactDOM from 'react-dom';

const Modal = ({children}) => 
  ReactDOM.createPortal(children, document.querySelector('#modal'));

export default Modal;
// App.js

function App () {

  const [visible, setVisible] = useState(false);

  const open = () => {
    setVisible(true)
  };

  const close = () => {
    setVisible(false)
  };

  return (
    <div>
      <button onClick={open}>Open</button>
      {visible && ( 
        <Modal>
          <div style={{
            width: '100vw',
            height: '100vh',
            background: 'rgba(0, 0, 0, 0.5)'
          }} 
          onClick={close}
          >
            Hello
          </div>
        </Modal>
      )}
    </div>
  );
}

forwardRef

// src/component/MyInput.jsx

import React from "react";

export default React.forwardRef(function MyInput (props, ref) {
  return (
    <div>
      <p>MyInput</p>
      <input ref={ref} />
    </div>
  );
});
// App.js

function App () {
  const myInputRef= useRef();

  const click = () => {
    console.log(myInputRef.current.value);
  };

  return (
    <div>
      <MyInput ref={myInputRef} />
      <button onClick={click}>send</button>
    </div>
  );
}
profile
성장하는 개발자 유슬이 입니다!

0개의 댓글