reactjs 为什么现在开发者在React中使用自定义钩子而不是服务?(Pre-hooks React开发人员的视角)

k10s72fa  于 2023-04-29  发布在  React
关注(0)|答案(2)|浏览(145)

我有多年的Java/Android/C#/Nodejs/Angular/React编程经验,但在钩子流行之前就停止了编写React,现在我回来了,我真的不明白为什么人们现在对自定义钩子如此着迷(这看起来很荒谬,因为对我来说,与其他框架相比,React/Redux的主要优势总是明确的简单性,我认为在引入钩子之前,带有两个简单类生命周期方法的React在其核心上是非常直观的,特别是对于Typescript接口)。
在几乎每一种当前语言中实现代码可重用性的标准方法是将事物重构为简单的纯函数到外部服务,这些服务可以轻松地导出/导入和测试,而不需要与组件/框架元素(所谓的“胶水”)混淆。很多时候,“控制反转”的整个应用程序就是基于此(和接口)。
现在我在很多地方读到“钩子是一种新的编码方式”,为所有东西编写自定义钩子是一种“好的实践”。有人能说服我这是真的吗?为什么?现在,这听起来像是某种mambo jambo,经典的“我们写了这个新的框架/库,因此它是世界上最好的东西”。
我会给予你一个简单的例子,我已经看到在一个教程。
当时的情况是这样的:

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

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

或者在重构之后:

componentDidMount(){
    documentService.setTitle(`You clicked ${count} times`);
}

componentDidUpdate(){
    documentService.setTitle(`You clicked ${count} times`);
}

对我来说看起来很好,就触发器操作而言,明确的意图是明确的(组件是触发服务,如果我们添加Typescript接口,我们可以在这里实现非常好的控制反转)。很多时候,服务可以只是通过 prop 。它非常简单,同样的逻辑可以用来说异步获取数据。
然后用钩子它的东西是这样的:

useEffect(() => {
    document.title = `You clicked ${count} times`;
  },[count]);

现在对我来说,它看起来和以前的生命周期方法模型几乎一样。但是代替两个单独的显式命名的生命周期方法,我们现在有依赖于“useEffect”方法和不同组合依赖数组的组合的生命周期(依赖数组的存在改变了方法的触发器)。是的,我意识到有差异,内部钩子的工作更像事件,但目标或多或少是相同的,基于组件中的一些变化触发动作/渲染。
没关系,在这种情况下,我会像以前一样对服务进行重构,如下所示:

useEffect(() => {
    documentService.setTitle(`You clicked ${count} times`);
  },[count]);

但现在我有个问题。我在很多地方读到,人们实际上并不这样做,他们现在为所有东西做定制挂钩,或多或少是这样的:

useDocumentTitle = (title: string) => {
  useEffect(() => {
    document.title = title
  }, [title])
}
useDocumentTitle(`You clicked ${count} times`);

1.然后我读到它更好,更可测试。我想的是“怎么做?现在,我们有useEffect钩子,它只是从组件中分离出来,但它并没有真正改变任何东西,因为“useDocumentTitle”与内部使用的useEffect具有相同的渲染生命周期?
1.所以现在我需要记住,函数useDocumentTitle可以触发组件的重新呈现,但我不知道它何时会在不查看此函数的情况下触发触发器,因为逻辑是基于内部使用的useEffect的依赖数组?
1.如何测试useDocumentTitle比服务或只是提取方法更容易?对我来说似乎更难。

mrphzbgm

mrphzbgm1#

useEffect是一个复杂的主题,React文档有6页讨论它。我不知道是谁说自定义钩子比单一的useEffect好得多,但这要看情况。
如果你只有一个单独的例子(甚至是一点重复),你需要useEffect在一个组件中做一些特定的事情,那么你绝对不需要一个自定义钩子。
自定义钩子是为了在组件之间共享逻辑,减少重复,并帮助您抽象逻辑。抽象逻辑使您不必担心“如何”实现某些东西,允许您通过告诉组件“做什么”来采取更具声明性的方法。

dy1byipe

dy1byipe2#

我不会详细介绍,但我只给予一个例子来说明为什么hook使代码更清晰:
假设你有一个组件会执行一些副作用:

class ClassComponent {
  componentDidMount() {
    element.addEventListener('keydown', this.doSomething);
  }
  componentWillUnmount() {
    element.removeEventListener('keydown', this.doSomething);
  }
  doSomething() {
    // Implementation
  }
}

当你有超过1个副作用时,很容易忘记在挂载组件时清理你已经做过的事情。但是使用钩子,你可以把创建和清除副作用放在一起:

function FunctionComponent() {
  useEffect(() => {
    function doSomething() {
      // Implementation
    }
    element.addEventListener('keydown', doSomething);
    return () => element.removeEventListener('keydown', doSomething);
  }, []);
}

这也使得创建共享库变得更容易,因为现在您所需要的只是一个执行上述useEffect的自定义钩子。
(在你的原始文章中缺少一件事是清理的想法。当React组件被卸载时,开发人员有责任确保该组件引起的所有副作用都恢复到原始状态。

相关问题