React Hooks 는 흔 한 구 덩이 를 사용 합 니 다.

19536 단어 ReactHooks쓰다
React Hooks 는 React 16.8 이 도입 한 새로운 특성 으로 클 라 스 를 사용 하지 않 는 전제 에서 state 와 다른 특성 을 사용 할 수 있 습 니 다.React Hooks 가 해결 해 야 할 문 제 는 상태 공유 로 render-props 와 higher-order components 에 이 어 세 번 째 상태 논리 재 활용 방안 으로 JSX 내장 지옥 문 제 는 발생 하지 않 습 니 다.
왜 훅 스 가 있 지?
Hooks 를 소개 하기 전에 먼저 React 의 구성 요소 생 성 방식 을 알려 드 려 야 합 니 다.하 나 는 클래스 구성 요소 이 고 하 나 는 순 함수 구성 요소 입 니 다.그리고 React 팀 은 구성 요소 가 복잡 한 용기 가 되 지 않도록 데이터 흐름 의 파이프 만 있 는 것 이 좋 습 니 다.개발 자 는 수요 에 따라 파 이 프 를 조합 하면 됩 니 다.즉,구성 요소 의 가장 좋 은 문법 은 클래스 가 아니 라 함수 여야 한 다 는 것 이다.
함수 구성 요 소 는 클래스 구성 요소 보다 업무 논리 코드 의 분리 와 구성 요소 의 재 활용 을 더욱 편리 하 게 실현 합 니 다.함수 구성 요소 도 클래스 구성 요소 보다 가 볍 습 니 다.react hooks 가 없 기 전에 함수 구성 요 소 는 LocalState 를 실현 할 수 없습니다.이 로 인해 localstate 상태 가 있 는 구성 요 소 는 함수 구성 요소 로 쓸 수 없습니다.이것 은 함수 구성 요소 의 응용 범 위 를 제한 합 니 다.react hooks 는 함수 구성 요소 의 능력 을 확장 시 켰 습 니 다.그러나 사용 하 는 과정 에서 도 아래 의 이런 문제 들 을 주의해 야 한다.그렇지 않 으 면 구덩이 에 빠 져 성능 손실 을 초래 할 수 있다.아래 의 방법 에 따라 해야만 이 함정 들 을 피 할 수 있다.
1.상태 변경 과 무관 한 변수 와 방법 을 구성 요소 함수 밖으로 추출
상태 가 바 뀔 때마다 모든 함수 구성 요 소 는 다시 실 행 됩 니 다.함수 구성 요소 내부 에서 정 의 된 방법 과 변 수 를 다시 만 들 고 메모 리 를 다시 할당 하면 성능 에 영향 을 줄 수 있 습 니 다.

import React, {useState,useCallback} from "react";

//          ,           
let testFooMemoAlloc = new Set();

const Page = (props:any) => {
  console.log('      ,          ')
  const [count, setCount] = useState(0);
  const calc = () => {
    setCount(count + 1);
  }

  const bar = {
    a:1,
    b:2,
    c: '          '
  }
 
  const doFoo = () => {
    console.log('        ');

  }
  testFooMemoAlloc.add(doFoo)
  
  return (
    <>
      <button onClick={calc}> 1</button>
      <p>count:{count}</p>
      <p>testFooMemoAlloc.size    ,            :{testFooMemoAlloc.size}</p>
    </>
  )
}

export default Page;

상태 변경 과 관련 된 변수 와 방법 은 hooks 구성 요소 에 넣 어야 합 니 다.상태 와 무관 한 변수 와 방법 이 없 으 면 함수 구성 요 소 를 추출 할 수 있 습 니 다.매번 상태 가 업데이트 되 지 않도록 메모리 를 재배 치 할 수 있 습 니 다.useMemo 와 useCallback 패키지 변수 와 함 수 를 각각 사용 할 수도 있 고 같은 효 과 를 얻 을 수 있 습 니 다.나중에 말씀 드 리 겠 습 니 다.

import React, {useState,useCallback} from "react";

//          ,           
let testFooMemoAlloc = new Set();

const bar = {
  a:1,
  b:2,
  c: '          '
}

const doFoo = () => {
  console.log('        ');

}

const Page = (props:any) => {
  console.log('      ,          ')
  const [count, setCount] = useState(0);
  const calc = () => {
    setCount(count + 1);
  }

  testFooMemoAlloc.add(doFoo)
  
  return (
    <>
      <button onClick={calc}> 1</button>
      <p>count:{count}</p>
      <p>testFooMemoAlloc.size    ,            :{testFooMemoAlloc.size}</p>
    </>
  )
}

export default Page;

2.하위 구성 요 소 를 memo 로 포장
부모 구성 요소 가 하위 구성 요 소 를 도입 하면 불필요 한 중복 렌 더 링 을 할 수 있 습 니 다.부모 구성 요소 가 count 를 업데이트 할 때마다 하위 구성 요 소 는 업 데 이 트 됩 니 다.

import React,{useState} from "react";
const Child = (props:any) => {
    console.log('   ?')
    return(
        <div>       </div>
    );
}
const Page = (props:any) => {
    const [count, setCount] = useState(0);
    return (
        <>
            <button onClick={(e) => { setCount(count+1) }}> 1</button>
            <p>count:{count}</p>
            <Child />
        </>
    )
}

export default Page;

메모 사용,count 변경 서브 구성 요소 가 업데이트 되 지 않 았 습 니 다.

import React,{useState,memo} from "react";
const Child = memo((props:any) => {
    console.log('   ?')
    return(
        <div>       </div>
    );
})
const Page = (props:any) => {
    const [count, setCount] = useState(0);
    return (
        <>
            <button onClick={(e) => { setCount(count+1) }}> 1</button>
            <p>count:{count}</p>
            <Child />
        </>
    )
}

export default Page;

memo 에 두 번 째 매개 변 수 를 입력 하고 대상 의 깊이 비 교 를 엽 니 다.하위 구성 요소 가 전달 하 는 속성 값 이 변경 되 지 않 았 을 때 하위 구성 요 소 는 무의미 한 render 를 하지 않 습 니 다.
memo 는 함수 구성 요소 뿐만 아니 라 class 구성 요소 에 도 적 용 됩 니 다.고급 구성 요소 입 니 다.기본 적 인 상황 에서 복잡 한 대상 에 대해 얕 은 층 만 비교 합 니 다.깊이 비 교 를 하려 면 두 번 째 매개 변 수 를 입력 할 수 있 습 니 다.shouldComponentUpdate와 달리 deep Compare 복귀true시 render 를 터치 하지 않 고 되 돌아 오 면false된다.반면shouldComponentUpdate은 정반 대 였 다.

import React, {useState, memo } from "react";
import deepCompare from "./deepCompare";

const Child = memo((props:any) => {
    console.log('   ')
  return (
      <>
      <div>       </div>
      <div>{ props.fooObj.a}</div>
      </>
    );
}, deepCompare)

const Page = (props:any) => {
  const [count, setCount] = useState(0);
  const [fooObj, setFooObj] = useState({ a: 1, b: { c: 2 } })
  console.log('      ')
  const calc = () => {
    setCount(count + 1);
    if (count === 3) {
      setFooObj({ b: { c: 2 }, a: count })
    }
  }
  const doBar = () => {
    console.log('        ,               ')
  }
    return (
        <>
        <button onClick={calc}> 1</button>
        <p>count:{count}</p>
        <Child fooObj={fooObj} doBar={doBar} />
        </>
    )
}

export default Page;

//             
export default function deepCompare(prevProps: any, nextProps: any) {
  const len: number = arguments.length;
  let leftChain: any[] = [];
  let rightChain: any = [];
  // // console.log({ arguments });
  //
  if (len < 2) {
    // console.log('    2   ,             ');
    return true;
  }
  // for (let i = 1; i < len; i++) {
  // leftChain = [];
  // rightChain = [];
  console.log({ prevProps, nextProps });
  if (!compare2Objects(prevProps, nextProps, leftChain, rightChain)) {
    // console.log('       ');
    return false;
  }
  // }
  // console.log('      ');

  return true;
}

function compare2Objects(prevProps: any, nextProps: any, leftChain: any, rightChain: any) {
  var p;

  //       NaN , js      ,              
  if (isNaN(prevProps) && isNaN(nextProps) && typeof prevProps === 'number' && typeof nextProps === 'number') {
    return true;
  }

  //      
  if (prevProps === nextProps) {
    console.log('   ', prevProps, nextProps);
    return true;
  }

  //       
  if (
    (typeof prevProps === 'function' && typeof nextProps === 'function') ||
    (prevProps instanceof Date && nextProps instanceof Date) ||
    (prevProps instanceof RegExp && nextProps instanceof RegExp) ||
    (prevProps instanceof String && nextProps instanceof String) ||
    (prevProps instanceof Number && nextProps instanceof Number)
  ) {
    console.log('function', prevProps.toString() === nextProps.toString());
    return prevProps.toString() === nextProps.toString();
  }

  //            null undefined,      
  if (!(prevProps instanceof Object && nextProps instanceof Object)) {
    console.log(prevProps, nextProps, 'prevProps instanceof Object && nextProps instanceof Object');
    return false;
  }

  if (prevProps.isPrototypeOf(nextProps) || nextProps.isPrototypeOf(prevProps)) {
    console.log('prevProps.isPrototypeOf(nextProps) || nextProps.isPrototypeOf(prevProps)');
    return false;
  }

  //               
  if (prevProps.constructor !== nextProps.constructor) {
    console.log('prevProps.constructor !== nextProps.constructor');
    return false;
  }

  //              
  if (prevProps.prototype !== nextProps.prototype) {
    console.log('prevProps.prototype !== nextProps.prototype');
    return false;
  }

  if (leftChain.indexOf(prevProps) > -1 || rightChain.indexOf(nextProps) > -1) {
    console.log('leftChain.indexOf(prevProps) > -1 || rightChain.indexOf(nextProps) > -1');
    return false;
  }

  //          ,          
  for (p in nextProps) {
    if (nextProps.hasOwnProperty(p) !== prevProps.hasOwnProperty(p)) {
      console.log('nextProps.hasOwnProperty(p) !== prevProps.hasOwnProperty(p)');
      return false;
    } else if (typeof nextProps[p] !== typeof prevProps[p]) {
      console.log('typeof nextProps[p] !== typeof prevProps[p]');
      return false;
    }
  }
  // console.log('p in prevProps');
  //          ,          
  for (p in prevProps) {
    //           
    if (nextProps.hasOwnProperty(p) !== prevProps.hasOwnProperty(p)) {
      console.log('nextProps.hasOwnProperty(p) !== prevProps.hasOwnProperty(p)');
      return false;
    }
    //           
    else if (typeof nextProps[p] !== typeof prevProps[p]) {
      console.log('typeof nextProps[p] !== typeof prevProps[p]');
      return false;
    }

    console.log('typeof prevProps[p]', typeof prevProps[p]);
    switch (typeof prevProps[p]) {
      //             
      case 'object':
      case 'function':
        leftChain.push(prevProps);
        rightChain.push(nextProps);

        if (!compare2Objects(prevProps[p], nextProps[p], leftChain, rightChain)) {
          console.log('!compare2Objects(prevProps[p], nextProps[p], leftChain, rightChain)');
          return false;
        }

        leftChain.pop();
        rightChain.pop();
        break;

      default:
        //        
        if (prevProps[p] !== nextProps[p]) {
          return false;
        }
        break;
    }
  }

  return true;
}

3.useCallback 으로 구성 요소 방법 포장
부모 구성 요소 가 하위 구성 요소 에 전달 하 는 방법 이 있 을 때 memo 는 아무런 효과 가 없 는 것 같 습 니 다.const 로 정의 하 는 방법 이 든 화살표 함수 나 bid 로 정의 하 는 방법 이 든 하위 구성 요 소 는 실 행 됩 니 다.

import React, { useState,memo } from 'react';
//             
interface ChildProps {
  changeName: ()=>void;
}
const FunChild = ({ changeName}: ChildProps): JSX.Element => {
  console.log('       ')
  return(
      <>
          <div>         </div>
          <button onClick={changeName}>         </button>
      </>
  );
}
const FunMemo = memo(FunChild);

const ArrowChild = ({ changeName}: ChildProps): JSX.Element => {
  console.log('       ')
  return(
      <>
          <div>         </div>
          <button onClick={changeName.bind(null,'test')}>         </button>
      </>
  );
}
const ArrowMemo = memo(ArrowChild);

const BindChild = ({ changeName}: ChildProps): JSX.Element => {
  console.log('Bind     ')
  return(
      <>
          <div>  Bind     </div>
          <button onClick={changeName}>Bind       </button>
      </>
  );
}
const BindMemo = memo(BindChild);

const Page = (props:any) => {
  const [count, setCount] = useState(0);
  const name = "test";

  const changeName = function() {
    console.log('          ,  useCallback ,             ');
  }

  return (
      <>
          <button onClick={(e) => { setCount(count+1) }}> 1</button>
          <p>count:{count}</p>
          <ArrowMemo  changeName={()=>changeName()}/>
          <BindMemo  changeName={changeName.bind(null)}/>
          <FunMemo changeName={changeName} />
      </>
  )
}

export default Page;

useCallback 을 사용 합 니 다.매개 변 수 는[]입 니 다.페이지 초기 렌 더 링 후 count 의 값 을 바 꿉 니 다.일반 함 수 를 전달 하 는 하위 구성 요 소 는 렌 더 링 하지 않 습 니 다.화살표 함수 와 bid 방식 으로 작성 하 는 방법 을 전달 하 는 하위 구성 요 소 는 렌 더 링 합 니 다.

import React, { useState,memo ,useCallback} from 'react';
//             
interface ChildProps {
  changeName: ()=>void;
}
const FunChild = ({ changeName}: ChildProps): JSX.Element => {
  console.log('       ')
  return(
      <>
          <div>         </div>
          <button onClick={changeName}>         </button>
      </>
  );
}
const FunMemo = memo(FunChild);

const ArrowChild = ({ changeName}: ChildProps): JSX.Element => {
  console.log('       ')
  return(
      <>
          <div>         </div>
          <button onClick={changeName.bind(null,'test')}>         </button>
      </>
  );
}
const ArrowMemo = memo(ArrowChild);

const BindChild = ({ changeName}: ChildProps): JSX.Element => {
  console.log('Bind     ')
  return(
      <>
          <div>  Bind     </div>
          <button onClick={changeName}>Bind       </button>
      </>
  );
}
const BindMemo = memo(BindChild);

const Page = (props:any) => {
  const [count, setCount] = useState(0);
  const name = "test";

  const changeName = useCallback(() => {
    console.log('          ,  useCallback ,             ');
  },[])

  return (
      <>
          <button onClick={(e) => { setCount(count+1) }}> 1</button>
          <p>count:{count}</p>
          <ArrowMemo  changeName={()=>changeName()}/>
          <BindMemo  changeName={changeName.bind(null)}/>
          <FunMemo changeName={changeName} />
      </>
  )
}

export default Page;

4.useMemo 로 구성 요소 의 대상 변 수 를 포장 합 니 다.
하위 구성 요소 가 memo,useCallback 을 사용 한 경우 하위 구성 요소 에 대상 속성 을 전달 합 니 다.대상 값 과 방법 이 변경 되 지 않 은 경우 부모 구성 요 소 는 상태 변경 과 상 관 없 이 하위 구성 요소 도 다시 렌 더 링 합 니 다.

import React, { useState,memo ,useCallback} from 'react';
//             -   memo,useCallback    ,             
interface ChildProps {
  childStyle: { color: string; fontSize: string;};
  changeName: ()=>void;
}
const FunChild = ({ childStyle,changeName}: ChildProps): JSX.Element => {
  console.log('       ')
  return(
      <>
          <div style={childStyle}>         </div>
          <button onClick={changeName}>         </button>
      </>
  );
}
const FunMemo = memo(FunChild);

const Page = (props:any) => {
  const [count, setCount] = useState(0);
  const childStyle = {color:'green',fontSize:'16px'};

  const changeName = useCallback(() => {
    console.log('          ,  useCallback ,             ');
  },[])

  return (
      <>
          <button onClick={(e) => { setCount(count+1) }}> 1</button>
          <p>count:{count}</p>
          <FunMemo childStyle={childStyle} changeName={changeName} />
      </>
  )
}

export default Page;

useMemo 를 사용 하면 하위 구성 요소 에 대상 속성 을 전달 할 때 업데이트 할 필요 가 없 는 문 제 를 해결 할 수 있 습 니 다.

import React, { useState,memo, useMemo, useCallback} from 'react';
//             
interface ChildProps {
  childStyle: { color: string; fontSize: string;};
  changeName: ()=>void;
}
const FunChild = ({ childStyle,changeName}: ChildProps): JSX.Element => {
  console.log('       ')
  return(
      <>
          <div style={childStyle}>         </div>
          <button onClick={changeName}>         </button>
      </>
  );
}
const FunMemo = memo(FunChild);

const Page = (props:any) => {
  const [count, setCount] = useState(0);
  const [name, setName] = useState("");
  const childStyle = {color:'green',fontSize:'16px'};

  const changeName = useCallback(() => {
    setName('     ')
  }, [])
  const childStyleMemo = useMemo(() => {
    return {
      color: name === '     ' ? 'red':'green',
      fontSize: '16px'
    }
  }, [name])

  return (
      <>
          <button onClick={(e) => { setCount(count+1) }}> 1</button>
          <p>count:{count}</p>
          <FunMemo childStyle={childStyleMemo} changeName={changeName} />
      </>
  )
}

export default Page;

이상 은 React Hooks 사용 피 갱 안내 에 대한 상세 한 내용 입 니 다.React Hooks 사용 에 관 한 자 료 는 저희 의 다른 관련 글 을 주목 해 주 십시오!

좋은 웹페이지 즐겨찾기