asp.net ajax 怎么获取前端ul li_useEffect Hook 是如何工作的(前端需要懂的知识点)

作者:Dave Ceddia译者:前端小智来源:daveceddia.

为了保证的可读性,本文采用意译而非直译。

想象一下:你有一个非常好用的函数组件,然后有一天,咱们需要向它添加一个生命周期方法。

呃…

刚开始咱们可能会想怎么能解决这个问题,然后最后变成,通常的做法是将它转换成一个类。但有时候咱们就是要用函数方式,怎么破?useEffect hook 出现就是为了解决这种情况。

使用useEffect,可以直接在函数组件内处理生命周期事件。 如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做 componentDidMountcomponentDidUpdatecomponentWillUnmount 这三个函数的组合。来看看例子:

import React, { useEffect, useState } from 'react';
import ReactDOM from 'react-dom';

function LifecycleDemo() {
  useEffect(() => {
    // 默认情况下,每次渲染后都会调用该函数
    console.log('render!');

    // 如果要实现 componentWillUnmount,
    // 在末尾处返回一个函数
    // React 在该函数组件卸载前调用该方法
    // 其命名为 cleanup 是为了表明此函数的目的,
    // 但其实也可以返回一个箭头函数或者给起一个别的名字。
    return function cleanup () {
        console.log('unmounting...');
    }
  })  
  return "I'm a lifecycle demo";
}

function App() {
  // 建立一个状态,为了方便
  // 触发重新渲染的方法。
  const [random, setRandom] = useState(Math.random());

  // 建立一个状态来切换 LifecycleDemo 的显示和隐藏
  const [mounted, setMounted] = useState(true);

  // 这个函数改变 random,并触发重新渲染
  // 在控制台会看到 render 被打印
  const reRender = () => setRandom(Math.random());

  // 该函数将卸载并重新挂载 LifecycleDemo
  // 在控制台可以看到  unmounting 被打印
  const toggle = () => setMounted(!mounted);

  return (
    <><button onClick={reRender}>Re-renderbutton><button onClick={toggle}>Show/Hide LifecycleDemobutton>
      {mounted && <LifecycleDemo/>}>
  );
}
ReactDOM.render(<App/>, document.querySelector('#root'));

单击“Show/Hide”按钮,看看控制台,它在消失之前打印“unmounting...”,并在它再次出现时打印 “render!”。

e29831727298fb1005d9032db61b56ba.gif

现在,点击Re-render按钮。每次点击,它都会打render!,还会打印umounting,这似乎是奇怪的。

f463ca593266f301008ba3adfad99094.gif

为啥每次渲染都会打印 'unmounting'。

咱们可以有选择性地从useEffect返回的cleanup函数只在组件卸载时调用。React 会在组件卸载的时候执行清除操作。正如之前学到的,effect 在每次渲染的时候都会执行。这就是为什么 React 会在执行当前 effect 之前对上一个 effect 进行清除。这实际上比componentWillUnmount生命周期更强大,因为如果需要的话,它允许咱们在每次渲染之前和之后执行副作用。

不完全的生命周期

useEffect在每次渲染后运行(默认情况下),并且可以选择在再次运行之前自行清理。

与其将useEffect看作一个函数来完成3个独立生命周期的工作,不如将它简单地看作是在渲染之后执行副作用的一种方式,包括在每次渲染之前和卸载之前咱们希望执行的需要清理的东西。

阻止每次重新渲染都会执行 useEffect

如果希望 effect 较少运行,可以提供第二个参数 - 值数组。 将它们视为该effect的依赖关系。 如果其中一个依赖项自上次更改后,effect将再次运行。

const [value, setValue] = useState('initial');

useEffect(() => {
  // 仅在 value 更改时更新
  console.log(value);
}, [value]) 

上面这个示例中,咱们传入 [value] 作为第二个参数。这个参数是什么作用呢?如果value的值是 5,而且咱们的组件重渲染的时候 value 还是等于 5,React 将对前一次渲染的 [5] 和后一次渲染的 [5] 进行比较。因为数组中的所有元素都是相等的(5 === 5),React 会跳过这个 effect,这就实现了性能的优化。

仅在挂载和卸载的时候执行

如果想执行只运行一次的 effect(仅在组件挂载和卸载时执行),可以传递一个空数组([])作为第二个参数。这就告诉 React 你的 effect 不依赖于 propsstate 中的任何值,所以它永远都不需要重复执行。这并不属于特殊情况 —— 它依然遵循依赖数组的工作方式。

useEffect(() => {
  console.log('mounted');
  return () => console.log('unmounting...');
}, []) 

这样只会在组件初次渲染的时候打印 mounted,在组件卸载后打印: unmounting

不过,这隐藏了一个问题:传递空数组容易出现bug。如果咱们添加了依赖项,那么很容易忘记向其中添加项,如果错过了一个依赖项,那么该值将在下一次运行useEffect时失效,并且可能会导致一些奇怪的问题。

只在挂载的时候执行

在这个例子中,一起来看下如何使用useEffectuseRef hook 将input控件聚焦在第一次渲染上。

import React, { useEffect, useState, useRef } from "react";
import ReactDOM from "react-dom";

function App() {
  // 存储对 input 的DOM节点的引用
  const inputRef = useRef();

  // 将输入值存储在状态中
  const [value, setValue] = useState("");

  useEffect(
    () => {
      // 这在第一次渲染之后运行
      console.log("render");
      // inputRef.current.focus();
    },
    // effect 依赖  inputRef
    [inputRef]
  );

  return (
    <inputref={inputRef}value={value}onChange={e => setValue(e.target.value)}
    />
  );
}
ReactDOM.render(<App />, document.querySelector("#root"));

在顶部,我们使用useRef创建一个空的ref。 将它传递给inputref prop ,在渲染DOM 时设置它。 而且,重要的是,useRef返回的值在渲染之间是稳定的 - 它不会改变。

因此,即使咱们将[inputRef]作为useEffect的第二个参数传递,它实际上只在初始挂载时运行一次。这基本上是 componentDidMount 效果了。

使用 useEffect 获取数据

再来看看另一个常见的用例:获取数据并显示它。在类组件中,无们通过可以将此代码放在componentDidMount方法中。在 hook 中可以使用 useEffect hook 来实现,当然还需要用useState来存储数据。

下面是一个组件,它从Reddit获取帖子并显示它们

import React, { useEffect, useState } from "react";
import ReactDOM from "react-dom";

function Reddit() {
  const [posts, setPosts] = useState([]);

  useEffect(async () => {
    const res = await fetch(
      "https://www.reddit.com/r/reactjs.json"
    );

    const json = await res.json();

    setPosts(json.data.children.map(c => c.data));
  }); // 这里没有传入第二个参数,你猜猜会发生什么?

  // Render as usual
  return (
    <ul>
      {posts.map(post => (<li key={post.id}>{post.title}li>
      ))}ul>
  );
}

ReactDOM.render(
  <Reddit />,
  document.querySelector("#root")
);

注意到咱们没有将第二个参数传递给useEffect,这是不好的,不要这样做。

不传递第二个参数会导致每次渲染都会运行useEffect。然后,当它运行时,它获取数据并更新状态。然后,一旦状态更新,组件将重新呈现,这将再次触发useEffect,这就是问题所在。

为了解决这个问题,我们需要传递一个数组作为第二个参数,数组内容又是啥呢。

useEffect所依赖的唯一变量是setPosts。因此,咱们应该在这里传递数组[setPosts]。因为setPostsuseState返回的setter,所以不会在每次渲染时重新创建它,因此effect只会运行一次。

当数据改变时重新获取

虚接着扩展一下示例,以涵盖另一个常见问题:如何在某些内容发生更改时重新获取数据,例如用户ID,名称等。

首先,咱们更改Reddit组件以接受subreddit作为一个prop,并基于该subreddit获取数据,只有当 prop 更改时才重新运行effect.

// 从props中解构`subreddit`:
function Reddit({ subreddit }) {
  const [posts, setPosts] = useState([]);

  useEffect(async () => {
    const res = await fetch(
      `https://www.reddit.com/r/${subreddit}.json`
    );

    const json = await res.json();
    setPosts(json.data.children.map(c => c.data));

    // 当`subreddit`改变时重新运行useEffect:
  }, [subreddit, setPosts]);

  return (
    <ul>
      {posts.map(post => (<li key={post.id}>{post.title}li>
      ))}ul>
  );
}

ReactDOM.render(
  <Reddit subreddit='reactjs' />,
  document.querySelector("#root")
);

这仍然是硬编码的,但是现在咱们可以通过包装Reddit组件来定制它,该组件允许咱们更改subreddit

function App() {
  const [inputValue, setValue] = useState("reactjs");
  const [subreddit, setSubreddit] = useState(inputValue);

  // Update the subreddit when the user presses enter
  const handleSubmit = e => {
    e.preventDefault();
    setSubreddit(inputValue);
  };

  return (
    <>
      
                  value={inputValue}          onChange={e => setValue(e.target.value)}        />                >  );}ReactDOM.render(, document.querySelector("#root"));

在 CodeSandbox 试试这个示例。

这个应用程序在这里保留了两个状态:当前的输入值和当前的subreddit。提交表单将提交subreddit,这会导致Reddit重新获取数据。

顺便说一下:输入的时候要小心,因为没有错误处理,所以当你输入的subreddit不存在,应用程序将会爆炸,实现错误处理就作为你们的练习。

各位可以只使用一个状态来存储输入,然后将相同的值发送到Reddit,但是Reddit组件会在每次按键时获取数据。

顶部的useState看起来有点奇怪,尤其是第二行:

const [inputValue, setValue] = useState("reactjs");
const [subreddit, setSubreddit] = useState(inputValue);

我们把reactjs的初值传递给第一个状态,这是有意义的,这个值永远不会改变。

那么第二行呢,如果初始状态改变了呢,如当你输入box时候。

记住useState是有状态的。它只使用初始状态一次,即第一次渲染,之后它就被忽略了。所以传递一个瞬态值是安全的,比如一个可能改变或其他变量的 prop

许许多多的用途

使用useEffect 就像瑞士军刀。它可以用于很多事情,从设置订阅到创建和清理计时器,再到更改ref的值。

componentDidMountcomponentDidUpdate 不同的是,在浏览器完成布局与绘制之后,传给 useEffect 的函数会延迟调用。这使得它适用于许多常见的副作用场景,比如如设置订阅和事件处理等情况,因此不应在函数中执行阻塞浏览器更新屏幕的操作。

然而,并非所有 effect 都可以被延迟执行。例如,在浏览器执行下一次绘制前,用户可见的 DOM 变更就必须同步执行,这样用户才不会感觉到视觉上的不一致。(概念上类似于被动监听事件和主动监听事件的区别。)React 为此提供了一个额外的 useLayoutEffect Hook 来处理这类 effect。它和 useEffect 的结构相同,区别只是调用时机不同。

虽然 useEffect 会在浏览器绘制后延迟执行,但会保证在任何新的渲染前执行。React 将在组件更新前刷新上一轮渲染的 effect

原文:https://daveceddia.com/useeffect-hook-examples/

代码部署后可能存在的BUG没法实时知道,事后为了解决这些BUG,花了大量的时间进行log 调试,这边顺便给大家推荐一个好用的BUG监控工具 Fundebug。

交流

为了回馈读者,《大迁世界》不定期举行(每个月一到三次),现金抽奖活动,保底200,外加用户赞赏,希望你能成为大迁世界的小锦鲤,快来试试吧

524f3a57c9939318d23152e994b1e401.png

延伸阅读

JS中,如何提高展开运算符的性能

JS 如何创建、读取和删除cookie

50 个JS 必须懂的面试题为你助力金九银十

JS 前20个常用字符串方法及使用方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/497697.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2018年全球5G的12大趋势

来源&#xff1a;5G概要&#xff1a;2018年全球5G的12大趋势行业观察未来智能实验室是人工智能学家与科学院相关机构联合成立的人工智能&#xff0c;互联网和脑科学交叉研究机构。由互联网进化论作者&#xff0c;计算机博士刘锋与中国科学院虚拟经济与数据科学研究中心石勇、刘…

java运行命令解释

-Dfile.encoding解释&#xff1a; 在命令行中输入java&#xff0c;在给出的提示中会出现-D的说明&#xff1a; -D<name><value> set a system property -D后面需要跟一个键值对&#xff0c;作用是通过命令行向java虚拟机传递一项系统属性 对-Dfile.…

服务器销售考核方案,电商后台:运营绩效系统总结

文章内容做者分离出来自身历经取每个人共享了电子商务情况中的运营业绩考核体系。业绩考核体系是明年5月份诸位发布的&#xff0c;通过一段时间运用&#xff0c;创造发明体系存已经一系列不了控果素&#xff0c;因此可以衷于一期的业绩考核体系虽然每一个月可以出示相关统计分析…

create 添加async和不添加的区别_鸽子饮水添加剂肝精与电解质的区别,不能混淆也不能代替...

肝精与电解质是鸽友们常用的两种饮水添加剂&#xff0c;虽说肝精与电解质都有清除药物残留的作用&#xff0c;但是&#xff0c;这两种添加剂的性质和功效是不一样的。有的混淆不清用电解质代替肝精&#xff0c;那是不对的。肝精就是肝精&#xff0c;电解质就是电解质&#xff0…

2017-2018互联网类脑巨系统研究报告,互联网大脑、城市云脑和AI

发布机构&#xff1a;未来智能实验室 报告人&#xff1a;刘锋、石勇、刘颖研究报告下载地址&#xff1a;https://pan.baidu.com/s/1pKVpX7l2008年1月1日&#xff0c;我们发表第一篇文章《互联网大脑进化示意图》&#xff0c;开始了互联网类脑架构研究&#xff0c;到今年正好1…

深入了解Struts2返回JSON数据的原理及具体应用范例

来源&#xff1a;http://yshjava.iteye.com/blog/1333104 早在我刚学Struts2之初的时候&#xff0c;就想写一篇文章来阐述Struts2如何返回JSON数据的原理和具体应用了&#xff0c;但苦于一直忙于工作难以抽身&#xff0c;渐渐的也淡忘了此事。直到前两天有同事在工作中遇到这个…

2018 AI 产品趋势(上):智能音箱的下半场,出路在何方

来源&#xff1a;36氪概要&#xff1a;AI时代&#xff0c;想必会也诞生新的巨头&#xff0c;接替前人站在浪潮之巅。但问题是&#xff0c;趋势前面&#xff0c;AI带来的机遇究竟在哪&#xff1f;科技真是迷人&#xff0c;他会眷顾每一代的年轻人。从沸腾的互联网时代&#xff0…

令牌桶 限速_Go 限流器实战系列(2) Token Bucket 令牌桶

上一篇说到 Leaky Bucket 能限制客户端的访问速率, 但是无法应对突发流量, 本质原因就是漏斗桶只是为了保证固定时间内通过的流量是一样的. 面对这种情况, 本篇文章继续介绍另外一种限流器: Token Bucket -- 令牌桶什么是 Token Bucket 漏斗桶的桶空间就那么大, 其只能保证桶里…

阿里巴巴年度技术总结:人工智能在搜索的应用和实践

来源&#xff1a;雷锋网概要&#xff1a;本文梳理了过去一年多搜索在深度学习方向上的探索&#xff0c;概要的介绍了我们在深度学习系统、深度学习算法和搜索应用落地的进展和思考。以深度学习为代表的人工智能在图像、语音和 NLP 领域带来了突破性的进展&#xff0c;在信息检索…

JSTL-EL表达式 函数fn

来源&#xff1a;http://blog.csdn.net/w__yi/article/details/7030843 JSTL-EL表达式 一个EL表达式包含变量和操作符。任何存储在某个JSP作用范围(如&#xff1a;page、 request、session、application)的bean能被作为一个EL变量来使用。 另外&#xff0c;EL支持以下预定义的…

omv检查硬盘坏道_坏道检测与修复

本软件提供了磁盘坏道检测功能及有限的坏道修复功能。为确保检查结果的准确性&#xff0c;建议在WinPE环境下进行检测&#xff0c;并且在检测坏道期间不要对磁盘做其他操作。1. 要使用本功能&#xff0c;首先选择需要检测坏道的磁盘&#xff0c;然后点击“磁盘 - 坏道检测与修复…

2018 年最值得期待的学术进展——致人工智能研究者们的年终总结

来源&#xff1a;AI科技评论概要&#xff1a;这里&#xff0c;我们为大家奉上机器学习学者 Alex Honcha 所展望的 2018 年最可能产生突破的 AI 领域。2017年马上就要过去了&#xff0c;而 AI 也在2017年中得到了快速发展。研究人员们提出了很多有趣而又富有开创性的工作。而作为…

python exchangelib 删除邮件_Python优雅的操作Exchange邮箱——exchangelib模块使用介绍...

最近想把公司邮箱的附件给下载下来&#xff0c;附件好多都是我整理的报告和文档&#xff0c;一个个去下载明显太傻&#xff0c;碰到这种问题第一个想到的就是Python啦需求很简单&#xff0c;只需要登录自己的Exchange邮箱&#xff0c;然后遍历所有邮件&#xff0c;有附件的就下…

对超长的文字换行处理:程序和CSS样式

css .text-overflow { display: block; /*内联对象需加*/ width: 125px; word-break: normal; white-space: pre-wrap; /* 不换行 */ overflow: hidden; /* 内容超出宽度时隐藏超出部分的内容 */ text-overflow: ellipsis; height: 30px; position: absolute; } <!--对超长…

DARPA盘点2017年最受关注的十大科技新闻

来源&#xff1a;国防科技要闻2017年&#xff0c;DARPA国防颠覆性技术与能力方面的重大投资覆盖了从量子超材料、机器学习、神经技术到无人系统自主性的数十个领域约250个项目。DARPA官网全年共收获3500万次访问量。根据访问量排序&#xff0c;DARPA整理出最受关注的十大技术新…

函数的凹凸性证明_理解图灵机和递归函数的等价性证明

背景之前读了 Martin Davis 的《Computability and Unsolvability》&#xff0c;决定对其中的图灵机和递归函数等价性证明做一个&#xff08;不严谨的&#xff09;整理&#xff0c;证明方法比较有趣&#xff0c;虽然最终结果并没有太大的惊喜。整理本身的目标是抛开晦涩难懂的数…

观点 | 别忽视深度学习的种种问题,Gary Marcus 泼冷水义不容辞

来源&#xff1a;AI科技评论纽约大学心理学教授 Gary Marcus 曾是 Uber 人工智能实验室的负责人&#xff0c;他自己创立的人工智能创业公司 Geometric Intelligence 2016 年 12 月被 Uber 收购&#xff0c;自己也就加入 Uber 帮助他们建立人工智能实验室。Gary Marcus 也曾号召…

spring框架做全局异常捕获_@ControllerAdvice注解(全局异常捕获)

背景ControllerAdvice 注解 通常用于定义ExceptionHandler&#xff0c; InitBinder和ModelAttribute 适用于所有RequestMapping方法的方法。ExceptionHandler异常处理器作用:可以拦截程序抛出来的指定异常。使用场景:主要使用与项目统一异常处理&#xff0c;对于rest风格的返回…

DeepMind推出「控制套件」:为「强化学习智能体」提供性能基准

来源&#xff1a;arxiv作者&#xff1a;Yuval Tassa, Yotam Doron, Alistair Muldal, Tom Erez,Yazhe Li, Diego de Las Casas, David Budden, Abbas Abdolmaleki, Josh Merel,Andrew Lefrancq, Timothy Lillicrap, Martin Riedmiller「雷克世界」编译&#xff1a;嗯~阿童木呀、…

JS中实现replaceAll的方法

http://fuleonardo.iteye.com/blog/339749 第一次发现JavaScript中replace() 方法如果直接用str.replace("-","!") 只会替换第一个匹配的字符. 而str.replace(/\-/g,"!")则可以全部替换掉匹配的字符(g为全局标志)。 replace() The replace()…