反应挂钩:What/Why`useEffect`?

React hooks: What/Why `useEffect`?

关于新提议React Effect Hook

  1. Effect hook (useEffect()) 的优点和用例是什么?

  2. 为什么它更可取?它与 componentDidMount/componentDidUpdate/componentWillUnmount(performance/readability)有何不同?

文档指出:

Mutations, subscriptions, timers, logging, and other side effects are not allowed inside the main body of a function component (referred to as React’s render phase).

但我认为在 componentDidUpdate 等生命周期方法而不是 render 方法中使用这些行为已经是常识。

还提到:

The function passed to useEffect will run after the render is committed to the screen.

但这不正是 componentDidMountcomponentDidUpdate 所做的吗?

这是来自 ReactConf2018 Dan Abramov 的 解释差异的演讲示例:


以下是从以下示例中得出的一些发现:

  1. 您将使用 hooks 编写更少的样板代码
  2. 使用 useEffect()
  3. 访问生命周期更新和状态更新
  4. 关于性能一方面是:

Unlike componentDidMount and componentDidUpdate, the function passed to useEffect fires after layout and paint, during a deferred event

  1. 代码共享太容易了,useEffect() 可以在同一组件内针对不同目的多次实现。
  2. 您可以通过将数组作为第二个参数传递给 useEffect() 挂钩来更有效地控制组件重新渲染,这在您仅将空数组 [] 传递给仅在安装和卸载时渲染组件时非常有效。
  3. 使用多个 useEffect() 挂钩来分离关注点并做出反应:

Hooks lets us split the code based on what it is doing rather than a lifecycle method name. React will apply every effect used by the component, in the order they were specified


使用 类:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }

  componentDidMount() {
    document.title = `You clicked ${this.state.count} times`;
  }

  componentDidUpdate() {
    document.title = `You clicked ${this.state.count} times`;
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

使用挂钩:

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
  1. What are the advantages and use cases of the Effect hook (useEffect())?

    优势

    主要是,钩子通常可以提取和重用跨多个组件通用的有状态逻辑,而无需高阶组件或渲染道具的负担。

    第二个好处(特别是 Effect hooks)是避免了错误,如果在 componentDidUpdate 中没有正确处理依赖于状态的副作用,可能会出现错误(因为 Effect hooks 确保这样的副作用是在每个渲染器上设置和拆除)。

    另请参阅下文详述的性能和可读性优势。

    用例

    任何使用生命周期方法实现有状态逻辑的组件——Effect 挂钩是 "Better Way"。

  2. Why would it be preferable & how does it differ over componentDidMount/componentDidUpdate/componentWillUnmount (performance/readability)?

    为什么更受欢迎

    由于上面和下面详述的优点。

    它与生命周期方法有何不同

    性能

    效果挂钩—

    • 感觉比生命周期方法响应更快,因为它们不会阻止浏览器更新屏幕;
    • 但是会在每个渲染上设置和拆除副作用,这可能很昂贵……
    • …因此可以优化为完全跳过,除非已更新特定状态。

    可读性

    效果挂钩导致:

    • 更简单且更易于维护的组件,因为能够将以前必须在同一组生命周期方法中表达的不相关行为拆分为每个此类行为的单个挂钩 - 例如:

      componentDidMount() {
        prepareBehaviourOne();
        prepareBehaviourTwo();
      }
      
      componentDidUnmount() {
        releaseBehaviourOne();
        releaseBehaviourTwo();
      }
      

      变成:

      useEffect(() => {
        prepareBehaviourOne();
        return releaseBehaviourOne;
      });
      
      useEffect(() => {
        prepareBehaviourTwo();
        return releaseBehaviourTwo;
      });
      

      请注意,与 BehaviourOne 相关的代码现在与与 BehaviourTwo 相关的代码明显分开,而在它混合在每个生命周期方法之前。

    • 更少的样板文件,因为消除了在多个生命周期方法中重复相同代码的需要(例如 componentDidMountcomponentDidUpdate 之间常见的代码)——例如:

      componentDidMount() {
        doStuff();
      }
      
      componentDidUpdate() {
        doStuff();
      }
      

      变成:

      useEffect(doStuff); // you'll probably use an arrow function in reality
      

useEffect 在状态改变时运行。

import { useState, useEffect } from 'react';
function Example() {
  const [Age, setAge] = useState(33);
  const [Somestate,setSomestate]=useState(initilaestate);
  useEffect(() => {
    console.log('the age is changed to ',Age);
  });

// you can use useEffect as many times you want in you component 
  useEffect(() => {
    console.log('the age is changed to ',Age);
  },[someState]);//here you tell useEffect what state to watch if you want to watch the changing of a  particular state and here we care about someState
  return (
    <div>
      <p>age increased to  {Age}</p>
      <button onClick={() => setAge(count + 1)}>
       Increase age by One
      </button>
    </div>
  );
}
```