๐Ÿ“– "React์—์„œ ๋ถˆํ•„์š”ํ•œ re-rendering component ๊ทธ๋งŒ!!"ํžˆ์Šคํ† ๋ฆฌ

12316 ๋‹จ์–ด javascriptfrontendreact
ํ•œ ๋ฒˆ ์‹œ๊ฐ„์— ๋”ฐ๋ผ...

๐Ÿ’Ž ํด๋ž˜์Šค ์ปดํฌ๋„ŒํŠธ ์ƒ์„ฑ



๐Ÿšฉ ์ˆœ์ˆ˜ ์ปดํฌ๋„ŒํŠธ()



์ƒˆ ํ•ญ๋ชฉ๊ณผ ์ด์ „ ํ•ญ๋ชฉ/์ƒํƒœ๋ฅผ ๋น„๊ตํ•˜์—ฌ ์ฐจ์ด๊ฐ€ ์—†์œผ๋ฉด ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋ Œ๋”๋ง๋ฉ๋‹ˆ๋‹ค.

๋น„๊ตํ•˜๋‹ค?? ๊ทธ๋Ÿฌ๋‚˜ ๊ทธ๋“ค์„ ๋น„๊ตํ•˜๋Š” ๋ฐฉ๋ฒ•??

<< React์—์„œ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒฝ์šฐ >>

  1. state changes
  2. parent component renders
  3. props changes
  4. shouldcomponentUpdate function returns true (I'll explain about it later)
  5. forceUpdate


์ˆซ์ž 1๊ณผ 2์˜ ๊ฒฝ์šฐ React๋Š” shallow compare์„ ํ†ตํ•ด ๋ Œ๋”๋งํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•ฉ๋‹ˆ๋‹ค.

์–•์€ ๋น„๊ต๋ž€ ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ฒ˜์Œ์—๋Š” ์ฐธ์กฐ๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค.
โ–ผ from this website

  • ์ฐธ์กฐ๋กœ ์ „๋‹ฌ(์–•์€ ์‚ฌ๋ณธ)
    ๋ณต์‚ฌ๋œ ์ปต์— ์ปคํ”ผ๋ฅผ ๋ถ€์œผ๋ฉด ์›๋ณธ ์ปต๋„ ํ•จ๊ป˜ ์ฑ„์›Œ์ง‘๋‹ˆ๋‹ค(๋‘ ๋ฐ์ดํ„ฐ๊ฐ€ ๋™์ผํ•œ ๋ฉ”๋ชจ๋ฆฌ ํ• ๋‹น ๊ณต๊ฐ„์— ์žˆ๊ธฐ ๋•Œ๋ฌธ)
  • ๊ฐ’์œผ๋กœ ์ „๋‹ฌ(๋”ฅ ์นดํ”ผ)
    ๋ณต์‚ฌํ•œ ์ปต์— ์ปคํ”ผ๋ฅผ ๋ถ€์œผ๋ฉด ์›๋ž˜ ์ปต์ด ์—ฌ์ „ํžˆ ๋น„์–ด ์žˆ์Œ

  • Javascript์—์„œ ๊ธฐ๋ณธ ๋ฐ์ดํ„ฐ ์œ ํ˜•(String, Number, Bigint, Boolean, Undefined, Symbol)์€ ๊ฐ’์œผ๋กœ ์ „๋‹ฌ๋˜๊ณ  Object, Array๋Š” ์ฐธ์กฐ๋กœ ์ „๋‹ฌ๋ฉ๋‹ˆ๋‹ค.

    ์†”์งํžˆ ์›์‹œ ๋ฐ์ดํ„ฐ ํƒ€์ž…๊ณผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์€ ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š์ง€๋งŒ Object์™€์˜ ๋น„๊ต์— ์‹ ๊ฒฝ์„ ์จ์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ๊ฐ์ฒด ์ฐธ์กฐ์˜ ๊ฒฝ์šฐ๋Š” ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

    import shallowCompare from 'react-addons-shallow-compare';
    
    const a = { country: "poland", country2: "japan" }
    const b = a
    
    console.log(shallowEqual(a, b))
    // true
    


    ๊ฐ์ฒด ์ฐธ์กฐ์˜ ๊ฒฝ์šฐ๊ฐ€ ๋‹ค๋ฆ„
  • ์ค‘์ฒฉ๋œ ๊ฐœ์ฒด๊ฐ€ ์•„๋‹˜

  • import shallowCompare from 'react-addons-shallow-compare';
    
    const a = { country: "poland", country2: "japan" }
    const b = { country: "poland", country2: "japan" }
    
    console.log(shallowEqual(a, b))
    // true
    


  • ์ค‘์ฒฉ ๊ฐœ์ฒด

  • import shallowCompare from 'react-addons-shallow-compare';
    
    const a = {
      country: "poland",
      coountry2: {
        city1: "tokyo",
        city2: "osaka"
      }
    }
    
    const b = {
      country: "poland", // country is primitive type, scalar data is the same -> true
      country2: { // country2 is object, so reference is different -> false
        city1: "tokyo",
        city2: "osaka"
      }
    }
    
    console.log(shallowEqual(a, b))
    // โญ false
    


    ๐Ÿšฉ shouldComponentUpdate()



    ๐Ÿ‘ฆ so it is ok all components are pure component, isn't it?
    ๐Ÿ‘ฉโ€๐Ÿ’ป no, because cost of comparing old and new state/props is high
    ๐Ÿ‘ฆ what should I do then?
    ๐Ÿ‘ฉโ€๐Ÿ’ป just decide comparing condition by yourself via "shouldComponentUpdate()"



    ์‹ค์ œ๋กœ PureComponent๋Š” shouldComponentUpdate()๋ฅผ ํ†ตํ•ด ๋ˆ„๊ตฐ๊ฐ€(ํŽ˜์ด์Šค๋ถ ํšŒ์‚ฌ์˜ ๋ˆ„๊ตฐ๊ฐ€)์— ์˜ํ•ด ๊ตฌํ˜„๋œ ๊ตฌ์„ฑ ์š”์†Œ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    // something like that
    class PureComponent extends React.Component {
        shouldComponentUpdate(nextProps, nextState) {
            return !(shallowEqual(this.props, nextProps) && shallowEqual(this.state, nextState));
        }
        โ€ฆ
    }
    



    ๐Ÿ’Ž ๊ธฐ๋Šฅ์  ๊ตฌ์„ฑ ์š”์†Œ ์ƒ์„ฑ



    2022๋…„ ์šฐ๋ฆฌ๋Š” ์ด ์„ธ๋Œ€

    ๐Ÿšฉ ๋ฐ˜์‘.๋ฉ”๋ชจ



    PureComponent() + shouldComponentUpdate()์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    // if new props changes, this component will be rendered
    const Button = React.memo(props => {
        return <div>{props.value}</div>
    })
    



    // if you put second argument, it is like shouldComponentUpdate()
    const Button = React.memo(
        props => {
            return <div>{props.value}</div>
        },
        (nextProps, prevProps) => {
            return nextProps.value === prevProps.value
        }
    )
    


    ๐Ÿšฉ ์‚ฌ์šฉ๋ฉ”๋ชจ



    ๐Ÿ‘ฆ what is useMemo? it is the same of React.memo?
    ๐Ÿ‘ฉโ€๐Ÿ’ป no, similar though. React.memo is added by React version16.6, and then React hook is added by version 16.8, useMemo as well.
    ๐Ÿ‘ฆ aha
    ๐Ÿ‘ฉโ€๐Ÿ’ป useMemo renders only when props changes because it remembers calculation result



    // when only "products props" changes, this component renders
    const Component: React.FC = ({ products }) => {
        const soldoutProducts = React.useMemo(() => products.filter(x => x.isSoldout === true), [products])
    }
    


    ๐Ÿšฉ useCallback



    ๋ถ€๋ชจ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž์‹ ์ปดํฌ๋„ŒํŠธ์—๊ฒŒ ํ•จ์ˆ˜์˜ props๋ฅผ ๋„˜๊ธฐ๋ฉด ์ƒˆ๋กœ์šด ํ•จ์ˆ˜(์‚ฌ์‹ค ํ•จ์ˆ˜๋Š” ๊ฐ์ฒด์˜ ํ•˜๋‚˜์ผ ๋ฟ)๊ฐ€ ๋งŒ๋“ค์–ด์ง„๋‹ค.
    ๊ทธ๊ฒƒ ๋•Œ๋ฌธ์— ์ž์‹ ๊ตฌ์„ฑ ์š”์†Œ๋Š” ์ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์ด ์ด์ „ ๊ธฐ๋Šฅ๊ณผ ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์„ ์ธ์‹ํ•˜๊ณ  ์Šฌํ”„๊ฒŒ๋„ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.

    โ†“ ์ž์‹/๋ถ€๋ชจ ๊ตฌ์„ฑ ์š”์†Œ ๊ฐ„์˜ ๋Œ€ํ™”

    ๐Ÿ‘จ Parentใ€Œre-renderiiingggg!! And now I recreated function that I have !!ใ€
    ๐Ÿ‘ผ Childใ€ŒMom!! Give me your function as props!!ใ€
    ๐Ÿ‘จ Parentใ€Œok I give you my function!ใ€
    ๐Ÿ‘ผ Childใ€Œwell now I need to confirm this objectโ€™s memory address is the same as object that I got before โ€ฆ. Hmmm different address, I also re-rendering!!!ใ€



    ์ด๋Ÿฌํ•œ ๋ถˆํ•„์š”ํ•œ ์žฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด useCallback์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

    ์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ