188体育怎么提现

通过鲁本小马丁内斯。

到目前为止,见多眼广的读者们,肯定已经浏览、浏览或至少收藏了六篇有关React 16.8最受期待的功能:钩子的文章。你可能已经读过或听说过它们有多好,有多糟糕,甚至可能有多困惑。你可能会问自己“我为什么要学这个?”你可能希望得到一个更好的答案"因为这是新事物".如果你遵循了一些钩子指南,你可能会发现自己在问“但为什么?我可以使用类做同样的事情!”

信贷@lizandmollie

如果这听起来很熟悉,那可能是因为我们每次面对学习新东西时都经历同样的循环。学习新东西对任何人来说都是困难的,重新学习你已经知道的东西尤其令人沮丧。你的本能反应可能是用你已经知道的东西来框定新事物。当我第一次在OkCupid上与我的团队分享我对钩子的了解时,我做了一个图表,映射组件生命周期方法来钩子替代品,这让我看188bet金宝搏官网起来有点像这个人:

作者附言:向OkCupid网站团队道歉,因为他们是我的实验对象188bet金宝搏官网

事实证明,这是一种非常令人困惑的学习钩子的方法!许多概念不能很好地映射,或者在一种方法与另一种方法之间看起来不必要地更加复杂。我不再继续谈论我的失败,而是开始谈论好的东西。这并不是一个全面的关于钩子的指南,但是我希望当您读完之后,您会有足够的兴趣来编写第一个使用钩子的组件。根据我的经验,这才是真正的秘密:在你开始为自己写之前,它不一定会点击。闲话少说,这是人类已知的学习钩子的最佳方法。

我是说没关系
这是我个人在出版时间发现的

累了:设置状态

连线:useState

我们从最基本的开始。您可能已经看到了对这个钩子的解释,如果是这样,请跳到下一节,在那里我们将开始进行更深入的讨论。

在React中,我们学到的第一件事就是创建一个有状态组件。您和我一样,通过扩展来学习编写组件反应。组件(或者更可能是使用React.createClass,但我们不谈论那些黑暗的日子)。你学会了使用这一点。setState({someKey: someValue})要修改组件的状态,请记住传递的键/值对设置状态用新值覆盖旧状态,其他所有内容就会合并进来。哦,不要忘记初始化状态对象这样当我们尝试时就不会出错设置状态.当然,别忘了.bind每个函数都会在构造函数中修改状态,或者记得使用箭头函数语法,你的团队中有人在几年前安装了Babel插件。

让我们暂时忘掉这一切。让我们概述一下构建一个简单的、有状态的点击计数器组件所需要的东西:

  1. 我们需要知道当前的点击计数(让我们调用它currentCount
  2. 我们需要一种方法来增加点击计数(让我们称之为setCurrentCount

如果我们想象一下,我们有这些先决条件,我们可以这样写:

从“React”中导入React;

const Counter = () => {
回报(
< div >
当前计数:{currentCount}

通常情况下我们可能会去设置状态要将其变为现实,就意味着必须将这个微小的功能组件重构为成熟的类组件。但等一下——这就是我们的第一个陷阱。

import React, {useState} from " React ";

const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);

回报(
< div >
当前计数:{currentCount}

“嗯,到底发生了什么事?!”你可能会问自己。寒冷,自我。这是一个钩子!钩子允许功能组件钩进以前只对类组件可用的特性,如状态。

useStateHook是一个接受单个参数的函数:初始状态(在本例中为0),并按顺序返回一个数组中的值和该状态值的setter。当您调用setter时,React会用更新后的状态值重新呈现组件,就像您调用时一样设置状态

“为什么数组解构?”你问?这样你就可以随便命名值和setter了。当然,你可以用useState在组件中,你可以随心所欲地多次钩子,这样你就可以在需要的时候跟踪多个状态,而不必将状态表示转换为对象。在下一节中,我们将更多地了解这为我们提供的机会。

累:单个对象保持状态

连线:针对不同关注点的不同状态。

关于useState你的组件的状态表示不是吗作为一个对象——它可以是一个数字,一个字符串,或者任何你想要的东西(包括一个对象)。但是这对于添加新的状态属性意味着什么呢?假设稍后您决定需要跟踪另一个有状态属性。当state是一个对象时,这就像添加另一个键一样简单。现在,它就像添加另一个调用一样简单useState

import React, {useState} from " React ";

const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);
const [isclick, setisclick] = useState(false);

回报(
< div >
当前计数:{currentCount}
点击:{isClicking}
<按钮
onClick={() => setCurrentCount(currentCount + 1)}
onMouseDown = {() = > setIsClicking (true)}
onMouseUp {() = > setIsClicking (false)} >
增量
< / >按钮
< / div >
);
};

这也使我们能够灵活地将相关的代码块分组在一起,而不是将可能不相关的状态更改分组在一起设置状态调用。例如,如果我想将一些事件处理程序移出返回块,我可以用最合适的代码进行分组,如下所示:

import React, {useState} from " React ";

const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);
const incrementCounter = () => setCurrentCount(currentCount + 1);

const [isclick, setisclick] = useState(false);
const onMouseDown = () => setisclick (true);
const onMouseUp = () => setisclick (false)

回报(
< div >
当前计数:{currentCount}
点击:{isClicking}
<按钮
onClick = {incrementCounter}
onMouseDown = {onMouseDown}
onMouseUp {onMouseUp} >
增量
< / >按钮
< / div >
);
};

很酷,对吧?在传统的类组件中,这些状态属性必须一起存在于单个对象中,并且状态的初始化和修改状态的函数可能会分散在整个组件中,而不是用相关的逻辑分组在一起。对于这么简单的组件,好处可能不大,但对于较大的组件,它确实会对组件的可读性产生影响。

累了:生命周期方法

连线:在需要更改时更改的数据

我们学到的useState可以取代(并在某些方面有所改进)设置状态.但是,我们能用类组件中的生命周期方法做的所有其他强大的事情呢?对于经验丰富的React开发人员来说,下面的内容可能会让他们感到不安。

生命周期方法是一种抽象,它让我们思考我们所处的组件呈现阶段。名字像componentDidMountcomponentDidUpdate,componentWillUnmount对于我们这些已经使用它们很多年的人来说感觉很直观,并且确切地知道它们什么时候和为什么会运行——这对于初学者来说是非常困惑的。也就是说,根据我的经验,我发现我们通常会以一些可预测的模式来使用它们。如果这些听起来很熟悉,请举手:

  1. componentDidMountcomponentWillUnmount用于附加/删除事件监听器,或设置/清除超时。(示例:侦听文档滚动或按键事件以更改状态)
  2. componentDidMountcomponentDidUpdate用于加载基于道具/状态变化的东西。(例如:当我们进入页面时加载数据,当状态改变时重新加载)
  3. componentDidMountcomponentDidUpdate用于根据道具/状态更改重新计算某些DOM属性。(例如:在状态改变后滚动到元素的顶部)

通常,我们同时使用几个这样的模式,哦,这些生命周期方法会变得很混乱吗?相关的逻辑必然会在这些方法中蔓延开来,并且很难理解在混乱中发生了什么。但事情并不一定是这样的!从根本上说,这些模式中的大多数都可以简化为:当事情发生时做一些事情。幸运的是,我们有一些钩子可以帮助解决这个问题。

假设我们想要删除计数器组件中的按钮,而只是侦听文档上的单击。与其编写生命周期方法来设置和拆除这些事件处理程序,不如使用一个名为useEffect

import React, {useState, useEffect} from " React ";

const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);
const incrementCounter = () => setCurrentCount(currentCount + 1);
useEffect (() = > {
文档。addEventListener(“点击”,incrementCounter);

Return () => {
文档。removeEventListener(“点击”,incrementCounter);
};
}, [incrementCounter]);

const [isclick, setisclick] = useState(false);
const onMouseDown = () => setisclick (true);
const onMouseUp = () => setisclick (false);
useEffect (() = > {
文档。addEventListener(“mousedown”,onMouseDown);
文档。addEventListener(“mouseup”,onMouseUp);

Return () => {
文档。removeEventListener(“mousedown”,onMouseDown);
文档。removeEventListener(“mouseup”,onMouseUp);
};
} [onMouseDown onMouseUp]);

回报(
< div >
当前计数:{currentCount}
点击:{isClicking}
< / div >
);
};

哇,很多啊。让我们关注一个新的useEffect块。

useEffect (() = > {
文档。addEventListener(“点击”,incrementCounter);

Return () => {
文档。removeEventListener(“点击”,incrementCounter);
};
});

这个整洁的小钩子可能很难理解——使用好的老式命名函数可能更容易理解(我想念那些):

useEffect(功能设置(){
文档。addEventListener(“点击”,incrementCounter);

返回函数tearDown() {
文档。removeEventListener(“点击”,incrementCounter);
};
});

这是更好的。本质上,我们告诉组件运行我们的设置()函数在其呈现后进行清理,并使用拆卸函数,在下一次渲染之前。例如,如果这个组件被渲染三次,它将运行如下函数:

  1. 渲染
  2. 设置()
  3. 渲染(x2)
  4. tearDown ()
  5. 设置()
  6. 渲染(x3)
  7. tearDown ()
  8. 设置()

…等等。但是,为了效率,我们可以选择不通过useEffect第二个参数:

useEffect(功能设置(){
文档。addEventListener(“点击”,incrementCounter);

返回函数tearDown() {
文档。removeEventListener(“点击”,incrementCounter);
};
}, [incrementCounter]);

第二个参数是应该导致组件重新运行的项列表设置拆卸功能。通常,这个列表将包括您在useEffect电话本例中,incrementCounter.这让我们避免了浪费的设置和拆卸。更强大的是,它可以帮助我们防止该效果运行不止一次,只需向它传递一个空值列表,其中包含要更改的值。有用的!

在上面的例子中,我们useEffect每次设置一些文档事件监听器incrementCounter但是我们可以使用这个钩子来运行任何我们想要的副作用——从订阅和取消订阅一个web套接字,当一些道具改变时点击API更新数据,或者任何其他我们可能想要采取的道具或状态驱动的操作。

在这一点上值得注意的是拆卸返回值是完全可选的。我们并不总是有想要清理的东西,但有时我们会清理,现在我们可以把相关的逻辑保持在一起。它也可以是一个有用的提醒,在我们的副作用后,我们可能会忘记清理componentWillUnmount

累了:组件的方法

连线:useCallback

“但是等等!”,你现在可能会说,我们在渲染函数中定义了incrementCounter !每次渲染都会重新定义,所以我们的钩子不会每次都运行吗?”好吧,好吧,我没有意识到您如此关注这个过度扩展的示例组件。但你完全正确!

import React, {useState, useEffect} from " React ";

const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);
const incrementCounter = () => setCurrentCount(currentCount + 1);

useEffect (() = > {
文档。addEventListener(“点击”,incrementCounter);

Return () => {
文档。removeEventListener(“点击”,incrementCounter);
};
}, [incrementCounter]);

回报(
< div >
当前计数:{currentCount}
< / div >
);
};

因为incrementCounter是被重新定义在每个渲染,使用它的第二个参数useEffect并没有给我们带来什么好处。谢天谢地,这里有个挂钩!

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

const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);
const incrementCounter = useCallback(
() => setCurrentCount(currentCount + 1),
[setCurrentCount, currentCount],
);

useEffect (() = > {
文档。addEventListener(“点击”,incrementCounter);

Return () => {
文档。removeEventListener(“点击”,incrementCounter);
};
}, [incrementCounter]);

回报(
< div >
当前计数:{currentCount}
< / div >
);
};

这是我最喜欢的,也是最有用的钩子之一,即使你放弃了钩子的整个概念,你也会想把它放在你的工具带里。你给useCallback一个函数作为它的第一个参数,它返回它的一个记忆版本,它只在第二个参数中的任何项发生变化时重新计算。

这是特别有用的,因为我们都知道向下传递箭头函数作为道具没有好,因为这可能导致浪费的重新提交。现在,解决这个问题就像把箭头函数包装在useCallback钩!这是一种简单的方法,可以挤出一些改进的性能,并防止不必要的重新呈现。

累了:重新选择

连线:useMemo

如果我现在不谈谈我的一个亲密的表亲,那我就太大意了useCallback,非常有用useMemo钩。当你发现自己在渲染块中计算一些昂贵的东西时,可以使用这个钩子。例如,如果你的组件体看起来像这样:

从“React”中导入React;

const MyComponent = ({someObject}) => {
const someNumber = Object.keys(someObject)
. map((关键)= > someObject(值))
.filter((value) => value % 2 === 0)
.reduce((sum, current) => sum + current, 0)
Const array =[…]新数组(someNumber)];

回报(
< div >
{array.map(() => )}
< / div >
);
};

(当然,这是一个荒谬的虚构的例子,但如果你一本正经地告诉我,你的代码库中没有这样的东西,我就把我的帽子吃了。)你可以把这个昂贵的计算包进去useMemo像这样:

import React, {useMemo} from " React ";

const MyComponent = ({someObject}) => {
const array = useMemo(() => {
const someNumber = Object.keys(someObject)
. map((关键)= > someObject(值))
.filter((value) => value % 2 === 0)
.reduce((sum, current) => sum + current, 0)
返回[…新数组(someNumber)];
}, [someObject]);

回报(
< div >
{array.map(() => )}
< / div >
);
};

现在,这个数组会只有的值,则重新计算自身someObject的变化。这比每次渲染都重新计算要高效得多(尽管仍然被承认比完全删除要低效得多,因为它非常糟糕™️)。在过去,图书馆喜欢重新选择为我们提供了获得类似性能好处的工具,但现在您无需导入额外的库就可以获得这些好处。

累:高阶组件/混合

连线:自定义钩子

一件事。回到我们的Counter示例(您认为我应该让Counter组件摆脱钩子——永远不!),如果我们出于一些难以理解的原因,想要在第二个组件中将单击处理程序附加到文档中,该怎么办?也许是一个点击就会产生随机数的。

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

const RandomNumberGenerator = () => {
const [randomNumber, setRandomNumber] = useState();
const getRandomNumber = useCallback(
() => setRandomNumber(4), //保证是随机的
(setRandomNumber),
);

useEffect (() = > {
文档。addEventListener(“点击”,getRandomNumber);

Return () => {
文档。removeEventListener(“点击”,getRandomNumber);
};
}, [getRandomNumber]);

回报(
< div >
随机数为:{randomNumber}
< / div >
);
};

好吧,我们可以在新组件中重新定义逻辑,但这并不有趣。如果我们觉得聪明的话,我们可以使用更高阶的组件,或者渲染道具来做这件事。但这正是定制钩子真正发挥作用的地方。我们可以将共享逻辑抽象到一个可以调用的自定义钩子useDocumentClick

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

函数useDocumentClick (onDocumentClick) {
useEffect (() = > {
文档。addEventListener(“点击”,onDocumentClick);

Return () => {
文档。removeEventListener(“点击”,onDocumentClick);
};
}, [onDocumentClick]);


const Counter = () => {
const [currentCount, setCurrentCount] = useState(0);
const incrementCounter = useCallback(
() => setCurrentCount(currentCount + 1),
[setCurrentCount, currentCount],
);
useDocumentClick (incrementCounter);

回报(
< div >
当前计数:{currentCount}
< / div >
);
};

const RandomNumberGenerator = () => {
const [randomNumber, setRandomNumber] = useState();
const getRandomNumber = useCallback(
() => setRandomNumber(4), //保证是随机的
(setRandomNumber),
);
useDocumentClick (getRandomNumber);

回报(
< div >
随机数为:{randomNumber}
< / div >
);
};

自定义钩子可以像使用其他钩子一样使用。自定义钩子的名字应该总是以使用,但除此之外,您可以在其中自由地做任何您想做的事情—包括使用其他钩子,如useStateuseEffect.组件永远不需要知道钩子的实现细节——只需要知道它的API。这可以帮助将复杂状态或副作用逻辑移出组件,并使该逻辑易于重用。您不一定希望对所有钩子都这样做,但这是在需要时使组件逻辑可重用的一种更简单的方法。

例如,如果您发现自己经常从组件进行API调用,您可以编写一个名为useAPI

function useAPI(方法,端点,数据){
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
const [response, setResponse] = useState(null);

使用效果(async () => {)
尝试{
setIsLoading(真正的);
setResponse(空);
setError(空);

Const res = await fetch(端点,{方法,数据});

setIsLoading(假);
setResponse (res);
}捕捉(err) {
setIsLoading(假);
setError(错);

},[方法,端点,数据]);

返回{
的反应,
错误,
isLoading,
};

这样,你就有了一个与组件API通信的一致层。如果您正在使用像GraphQL和Apollo这样的现代技术,就像我们在OkCupid上开始使用的那样,已经有一些了188bet金宝搏官网伟大的开源项目为您提供一些这些强大的自定义钩子,以及不断增长的集合其他配套工具挂钩

一个警告⚠️

在使用钩子时,你必须记住一个主要规则:你的钩子必须每次组件呈现时,都以相同的顺序声明。这意味着:钩子不能在条件语句内部、条件返回后或循环中定义。钩子必须总是在缩进的“顶层”被调用。如果这看起来很奇怪,那是因为按照Javascript的标准,这是一个不寻常的限制。这是语言之上的额外约束,但对于React能够以正确的方式保存状态来说是必要的。关于为什么存在这个限制的更多信息,我建议您阅读丹·阿布拉莫夫的博客“反应过度”.好消息是:有一个eslint插件来帮助你避免犯错。

你上钩了吗?

React钩子确实可以改变我们对组件中的状态和状态更新的思考方式,这可能会带来一些非常好的重构机会。虽然将我们的组件1:1地从类“转换”到钩子是很诱人的,但这通常会限制钩子所能提供的好处。我希望本指南能帮助您对钩子的强大功能产生兴趣,并帮助我们重新思考组件中的一些常见模式。优化现有代码的机会useCallbackuseMemo不能夸大,因为它们可以在我们现有的功能组件中提供一些简单的性能优势。关于什么时候使用钩子比使用类组件更直观的争论肯定会很激烈,但我认为至少钩子为我们提供了一些非常强大的新工具,用于表达有状态组件,甚至优化无状态组件。

最初发表在https://tech.188bet金宝搏官网okcupid.com2019年2月27日。

188bet金宝搏官网OkCupid科技博客

阅读来自OkCupid工程团队的故事,每天连188bet金宝搏官网接着数百万人

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid的工程团队负责每天为数百万人配对。在OkCupid科技博客上阅读他们的故事188bet金宝搏官网

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid科技博客

188bet金宝搏官网OkCupid的工程团队负责每天为数百万人配对。在OkCupid科技博客上阅读他们的故事188bet金宝搏官网