반응 후크와 클래스의 차이점은 무엇입니까?

青灯夜游
풀어 주다: 2022-03-22 12:12:22
원래의
8380명이 탐색했습니다.

차이점: 1. 후크는 클래스보다 더 간결하게 작성됩니다. 2. 후크의 비즈니스 코드는 클래스보다 더 집계됩니다. 3. 클래스 구성 요소의 논리 재사용은 일반적으로 렌더링 소품과 HOC를 사용하는 반면, 반응 후크는 논리를 재사용하기 위한 사용자 정의 후크를 제공합니다. .

반응 후크와 클래스의 차이점은 무엇입니까?

이 튜토리얼의 운영 환경: Windows 7 시스템, 반응 버전 17.0.1, Dell G3 컴퓨터.

반응 후크와 클래스 구성 요소의 차이점은 무엇입니까? 반응 후크와 클래스 구성 요소를 비교하고 차이점에 대해 이야기해 보겠습니다.

react-hooks로 해결되는 문제

  • 함수 구성 요소는 자체 상태를 가질 수 없습니다. Hooks 이전에는 함수 구성 요소가 Stateless였으며 부모 구성 요소의 상태는 props를 통해 획득되었지만 Hook은 함수 구성 요소의 내부 상태를 유지하기 위해 useState를 제공합니다.

  • 기능 컴포넌트에서는 컴포넌트의 수명주기를 모니터링할 수 없습니다. useEffect는 여러 수명주기 함수를 집계합니다.

  • 클래스 구성 요소의 수명 주기는 더 복잡합니다(버전 15에서 버전 16으로 변경 사항이 큽니다).

  • 클래스 구성 요소 로직은 재사용하기 어렵습니다(HOC, 렌더링 소품). 클래스와 비교 한 후크의 비교 (비교)

1은 더 간결합니다.

훅을 사용한 코드가 클래스 컴포넌트 코드보다 더 간결하고 명확하다는 것을 알 수 있습니다.

2. 비즈니스 코드가 더 집계됩니다

클래스 구성 요소를 사용할 때 함수가 두 개의 수명 주기 함수에 나타나는 경우가 종종 있습니다. 예:

class ExampleOfClass extends Component {
  constructor(props) {
    super(props)
    this.state = {
      count: 1
    }
  }
  handleClick = () => {
    let { count } = this.state
    this.setState({
      count: count+1
    })
  }
  render() {
    const { count } = this.state
    return (
      <div>
        <p>you click { count }</p>
        <button onClick={this.handleClick}>点击</button>
      </div>
    )
  }
}
로그인 후 복사

타이머 추가와 타이머 지우기는 서로 다른 두 가지 수명주기 기능에 있기 때문에 그 사이에 다른 비즈니스 코드가 많이 있을 수 있으므로 타이머 지우기가 추가되지 않은 경우 타이머 지우기를 잊어버릴 수 있습니다. 구성 요소가 제거되면 서버 기능으로 인해 메모리 누수 및 지속적인 네트워크 요청 등의 문제가 발생할 수 있습니다. 그러나 후크를 사용하면 코드를 더 중앙 집중화하고 관리하기 쉽게 만들 수 있으며 잊어버리기 쉽지 않습니다.

function ExampleOfHooks() {
    const [count, setCount] = useState(0)
    const handleClick = () => {
        setCount(count + 1)
    }
    return (
      <div>
        <p>you click { count }</p>
        <button onClick={handleClick}>点击</button>
      </div>
    )
}
로그인 후 복사

3. 로직 재사용이 편리합니다.

클래스 구성 요소의 로직 재사용은 일반적으로 렌더링 소품과 HOC를 사용합니다. React Hooks는 로직을 재사용하기 위한 사용자 정의 후크를 제공합니다.

다음은 페이지에서 마우스 위치를 얻기 위한 로직 재사용의 예입니다.

클래스 컴포넌트 렌더링 소품 재사용

let timer = null
componentDidMount() {
    timer = setInterval(() => {
        // ...
    }, 1000)
}
// ...
componentWillUnmount() {
    if (timer) clearInterval(timer)
}
로그인 후 복사

custom Hooks 재사용

useEffect(() => {
    let timer = setInterval(() => {
        // ...
    }, 1000)
    return () => {
        if (timer) clearInterval(timer)
    }
}, [//...])
로그인 후 복사

훅이 사용되는 것을 명확하게 볼 수 있습니다. 로직을 재사용하는 것이 더 편리하고, 사용하면 로직이 더 명확해집니다.

hooks 일부 일반적인 API는

1, useState

구문

이 구문은 ES6 배열 구조이며, 배열의 첫 번째 값은 선언된 상태이고 두 번째는 각 값입니다. 상태를 바꾸는 함수이다.

각 프레임에는 독립된 상태가 있습니다

개인적으로는 각 프레임의 독립된 상태가 클로저 방식을 사용하여 구현된 것으로 알고 있습니다.
import React, { Component } from &#39;react&#39;

class MousePosition extends Component {
  constructor(props) {
    super(props)
    this.state = {
      x: 0,
      y: 0
    }
  }

  handleMouseMove = (e) => {
    const { clientX, clientY } = e
    this.setState({
      x: clientX,
      y: clientY
    })
  }

  componentDidMount() {
    document.addEventListener(&#39;mousemove&#39;, this.handleMouseMove)
  }

  componentWillUnmount() {
    document.removeEventListener(&#39;mousemove&#39;, this.handleMouseMove)
  }

  render() {
    const { children } = this.props
    const { x, y } = this.state
    return(
      <div>
        {
          children({x, y})
        }
      </div>
    )
  }

}

// 使用
class Index extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    return (
      <MousePosition>
        {
          ({x, y}) => {
            return (
              <div>
                <p>x:{x}, y: {y}</p>
              </div>
            )
          }
        }
      </MousePosition>
    )
  }
}

export default Index
로그인 후 복사

컴포넌트의 상태나 소품이 업데이트되면 함수 컴포넌트가 렌더링을 위해 다시 호출되며, 각 렌더링은 독립적이며 고유한 독립적인 소품과 상태를 가지며 이는 다른 렌더링에 영향을 주지 않습니다.

2.useEffect

const [value, setValue] = useState(0)

Syntax

import React, { useEffect, useState } from &#39;react&#39;

function usePosition() {
  const [x, setX] = useState(0)
  const [y, setY] = useState(0)

  const handleMouseMove = (e) => {
    const { clientX, clientY } = e
    setX(clientX)
    setY(clientY)
  } 

  useEffect(() => {
    document.addEventListener(&#39;mousemove&#39;, handleMouseMove)
    return () => {
      document.removeEventListener(&#39;mousemove&#39;, handleMouseMove)
    }
  })
  return [
    {x, y}
  ]
}

// 使用
function Index() {
  const [position] = usePosition()
  return(
    <div>
      <p>x:{position.x},y:{position.y}</p>
    </div>
  )
}

export default Index
로그인 후 복사
useEffect는 콜백 함수와 종속성을 전달받으며, 내부의 콜백 함수는 종속성이 변경될 때만 실행됩니다. useEffect는 클래스 구성 요소 didMount, didUpdate 및 willUnmount의 수명 주기 기능과 유사합니다.

주의사항

useEffect는 비동기식이며 구성요소 렌더링이 완료된 후 실행됩니다.

useEffect의 콜백 함수는 부작용을 제거하거나

if를 반환하지 않는 처리 함수만 반환할 수 있습니다. useEffect가 전달됩니다. 종속성이 빈 배열이면 useEffect 내부 함수는 한 번만 실행됩니다

3. useMemo, useCallback
  • useMemo 및 useCallback은 주로 구성 요소 업데이트 수를 줄이고 구성 요소를 최적화하는 데 사용됩니다. 성능.

  • useMemo는 콜백 함수와 종속성을 전달받으며, 종속성이 변경된 경우에만 콜백 함수가 다시 실행됩니다.

  • useCallback은 콜백 함수와 종속성을 수신하고, 기억된 버전의 콜백 함수를 반환합니다. 기억된 버전은 종속성이 변경될 때만 다시 기억됩니다.

Syntax

function Example() {
  const [val, setVal] = useState(0)
  const timeoutFn = () => {
      setTimeout(() => {
        // 取得的值是点击按钮的状态,不是最新的状态
          console.log(val)
      }, 1000)
  }
  return (
      <>
          <p>{val}</p>
          <button onClick={()=>setVal(val+1)}>+</button>
          <button onClick={timeoutFn}>alertNumber</button>
      </>
  )
}
로그인 후 복사

우리는 일반적으로 클래스 컴포넌트에 대해 React.PureComponent를 사용합니다. PureComponent는 shouldUpdate에서 비교를 수행하여 함수 컴포넌트에 대해 업데이트가 필요한지 결정합니다. 우리는 일반적으로 React를 사용합니다. 메모. 하지만 React Hooks를 사용하면 각 렌더링 업데이트가 독립적이므로(새 상태가 생성됨) React.memo를 사용하더라도 여전히 다시 렌더링됩니다.

比如下面这种场景,改变子组件的name值后由于父组件更新后每次都会生成新值(addAge函数会改变),所以子组件也会重新渲染。

function Parent() {
  const [name, setName] = useState(&#39;cc&#39;)
  const [age, setAge] = useState(22)

  const addAge = () => {
    setAge(age + 1)
  }

  return (
    <>
      <p>父组件</p>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>age: {age}</p>
      <p>-------------------------</p>
      <Child addAge={addAge} />
    </>
  )
}

const Child = memo((props) => {
  const { addAge } = props
  console.log(&#39;child component update&#39;)
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})
로그인 후 복사

使用useCallback优化

function Parent() {
  const [name, setName] = useState(&#39;cc&#39;)
  const [age, setAge] = useState(22)

  const addAge = useCallback(() => {
    setAge(age + 1)
  }, [age])

  return (
    <>
      <p>父组件</p>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <p>age: {age}</p>
      <p>-------------------------</p>
      <Child addAge={addAge} />
    </>
  )
}

const Child = memo((props) => {
  const { addAge } = props
  console.log(&#39;child component update&#39;)
  return (
    <>
      <p>子组件</p>
      <button onClick={addAge}>click</button>
    </>
  )
})
로그인 후 복사

只有useCallback的依赖性发生变化时,才会重新生成memorize函数。所以当改变name的状态是addAge不会变化。

4、useRef

useRef类似于react.createRef。

const node = useRef(initRef)
로그인 후 복사

useRef 返回一个可变的 ref 对象,其 current 属性被初始化为传入的参数(initRef)

作用在DOM上

const node = useRef(null)
<input ref={node} />
로그인 후 복사

这样可以通过node.current属性访问到该DOM元素。

需要注意的是useRef创建的对象在组件的整个生命周期内保持不变,也就是说每次重新渲染函数组件时,返回的ref 对象都是同一个(使用 React.createRef ,每次重新渲染组件都会重新创建 ref)。

5、useReducer

useReducer类似于redux中的reducer。

语法

const [state, dispatch] = useReducer(reducer, initstate)
로그인 후 복사

useReducer传入一个计算函数和初始化state,类似于redux。通过返回的state我们可以访问状态,通过dispatch可以对状态作修改。

const initstate = 0;
function reducer(state, action) {
  switch (action.type) {
    case &#39;increment&#39;:
      return {number: state.number + 1};
    case &#39;decrement&#39;:
      return {number: state.number - 1};
    default:
      throw new Error();
  }
}
function Counter(){
    const [state, dispatch] = useReducer(reducer, initstate);
    return (
        <>
          Count: {state.number}
          <button onClick={() => dispatch({type: &#39;increment&#39;})}>+</button>
          <button onClick={() => dispatch({type: &#39;decrement&#39;})}>-</button>
        </>
    )
}
로그인 후 복사

6、useContext

通过useContext我们可以更加方便的获取上层组件提供的context。

父组件

import React, { createContext, Children } from &#39;react&#39;
import Child from &#39;./child&#39;

export const MyContext = createContext()

export default function Parent() {

  return (
    <div>
      <p>Parent</p>
      <MyContext.Provider value={{name: &#39;cc&#39;, age: 21}}>
        <Child />
      </MyContext.Provider>
    </div>
  )
}
로그인 후 복사

子组件

import React, { useContext } from &#39;react&#39;
import { MyContext } from &#39;./parent&#39;

export default function Parent() {
  const data = useContext(MyContext) // 获取父组件提供的context
  console.log(data)
  return (
    <div>
      <p>Child</p>
    </div>
  )
}
로그인 후 복사

使用步骤

  • 父组件创建并导出context:export const MyContext = createContext()
  • 父组件使用providervalue提供值:<MyContext.provide value={{name: &#39;cc&#39;, age: 22}} />
  • 子组件导入父组件的context:import { MyContext } from &#39;./parent&#39;
  • 获取父组件提供的值:const data = useContext(MyContext)

不过在多数情况下我们都不建议使用context,因为会增加组件的耦合性。

7、useLayoutEffect

useEffect 在全部渲染完毕后才会执行;useLayoutEffect 会在 浏览器 layout之后,painting之前执行,并且会柱塞DOM;可以使用它来读取 DOM 布局并同步触发重渲染。

export default function LayoutEffect() {
  const [color, setColor] = useState(&#39;red&#39;)
  useLayoutEffect(() => {
      alert(color) // 会阻塞DOM的渲染
  });
  useEffect(() => {
      alert(color) // 不会阻塞
  })
  return (
      <>
        <div id="myDiv" style={{ background: color }}>颜色</div>
        <button onClick={() => setColor(&#39;red&#39;)}>红</button>
        <button onClick={() => setColor(&#39;yellow&#39;)}>黄</button>
      </>
  )
}
로그인 후 복사

上面的例子中useLayoutEffect会在painting之前执行,useEffect在painting之后执行。

hooks让函数组件拥有了内部状态、生命周期,使用hooks让代码更加的简介,自定义hooks方便了对逻辑的复用,并且摆脱了class组件的this问题;但是在使用hooks时会产生一些闭包问题,需要仔细使用。

【相关推荐:Redis视频教程

위 내용은 반응 후크와 클래스의 차이점은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
최신 이슈
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿