ReactJS 教程

ReactJS - 主页 ReactJS - 简介 ReactJS - 路线图 ReactJS - 安装 ReactJS - 功能 ReactJS - 优势和缺点 ReactJS - 架构 ReactJS - 创建 React 应用程序 ReactJS - JSX ReactJS - 组件 ReactJS - 嵌套组件 ReactJS - 使用组件 ReactJS - 集合组件 ReactJS - 样式 ReactJS - 属性 (props) ReactJS - 使用属性创建组件 ReactJS - props 验证 ReactJS - 构造函数 ReactJS - 组件生命周期 ReactJS - 事件管理 ReactJS - 创建事件感知组件 ReactJS - Expense Manager 事件 ReactJS - 状态管理 ReactJS - 状态管理 API ReactJS - 无状态组件 ReactJS - Hooks 进行状态管理 ReactJS - Hooks 的组件生命周期 ReactJS - 布局组件 ReactJS - 分页 ReactJS - Material UI ReactJS - Http 客户端编程 ReactJS - 表单编程 ReactJS - 受控组件 ReactJS - 非受控组件 ReactJS - Formik ReactJS - 条件渲染 ReactJS - 列表 ReactJS - Key 键 ReactJS - 路由 ReactJS - Redux ReactJS - 动画 ReactJS - Bootstrap ReactJS - Map ReactJS - 表格 ReactJS - 使用 Flux 管理状态 ReactJS - 测试 ReactJS - CLI 命令 ReactJS - 构建和部署 ReactJS - 示例

Hooks

ReactJS - Hooks 简介 ReactJS - 使用 useState ReactJS - 使用 useEffect ReactJS - 使用 useContext ReactJS - 使用 useRef ReactJS - 使用 useReducer ReactJS - 使用 useCallback ReactJS - 使用 useMemo ReactJS - 自定义 Hooks

ReactJS 高级

ReactJS - 可访问性 ReactJS - 代码拆分 ReactJS - 上下文 ReactJS - 错误边界 ReactJS - 转发 Refs ReactJS - 片段 ReactJS - 高阶组件 ReactJS - 与其他库集成 ReactJS - 优化性能 ReactJS - Profiler API ReactJS - Portals ReactJS - 不使用 ES6 ECMAScript ReactJS - 不使用 JSX 的 React ReactJS - Reconciliation ReactJS - Refs 和 DOM ReactJS - 渲染道具 ReactJS - 静态类型检查 ReactJS - 严格模式 ReactJS - Web 组件

其他概念

ReactJS - 日期选择器 ReactJS - Helmet ReactJS - 内联样式 ReactJS - PropTypes ReactJS - BrowserRouter ReactJS - DOM ReactJS - 轮播 ReactJS - 图标 ReactJS - 表单组件 ReactJS - 参考 API

ReactJS 有用资源

ReactJS - 快速指南 ReactJS - 备忘录 Axios - 备忘录 ReactJS - 有用资源 ReactJS - 讨论


ReactJS - 使用 useEffect

React 提供 useEffect 来在组件中执行副作用。一些副作用如下 −

  • 从外部源获取数据并更新渲染的内容。

  • 渲染后更新 DOM 元素。

  • 订阅

  • 使用计时器

  • 日志记录

在基于类的组件中,这些副作用是使用生命周期组件完成的。因此,useEffect Hooks(钩子)是下面提到的生命周期事件的效果替代品。

  • componentDidMount −首次渲染完成后触发。

  • componentDidUpdate − 由于 prop 或 state 更改而更新渲染后触发。

  • componentWillUnmount − 在组件销毁期间卸载渲染内容后触发。

本章让我们学习如何使用 effect hook。

useEffect 的签名

useEffect 的签名如下 −

useEffect( <update function>, <dependency> )

其中,update 函数的签名如下 −

{
   // code
   return <clean up function>
}

这里,

Update function − Update function 是每次渲染阶段后执行的函数。这对应于 componentDidMountcomponentDidUpdate 事件

Dependency − Dependency 是一个包含函数所依赖的所有变量的数组。指定依赖关系对于优化 effect hook 非常重要。一般来说,update function 会在每次渲染后调用。有时没有必要在每次渲染时都渲染 update function。假设我们从外部源获取数据,并在渲染阶段之后对其进行更新,如下所示 −

const [data, setDate] = useState({})
const [toggle, setToggle] = useState(false)
const [id, setID] = useState(0)
useEffect( () => {
    fetch('/data/url/', {id: id}).then( fetchedData => setData(fetchedData) )
})
// code

只要更新 datatoggle 变量,组件就会重新渲染。但如您所见,我们不需要在每次更新切换状态时运行定义的效果。要解决此问题,我们可以传递一个空依赖项,如下所示 −

const [data, setDate] = useState({})
const [toggle, setToggle] = useState(false)
const [id, setID] = useState(0)
useEffect( () => {
   fetch('/data/url/', { id: id }).then( fetchedData => setData(fetchedData) )
}, [])

上述代码在第一次渲染后只会运行一次效果。即使它可以解决问题,每次更改 id 时都必须运行效果。为了实现这一点,我们可以将 id 作为效果的依赖项,如下所示 −

const [data, setDate] = useState({})
const [toggle, setToggle] = useState(false)
const [id, setID] = useState(0)
useEffect( () => {
    fetch('/data/url/', { id: id }).then( fetchedData => setData(fetchedData) )
}, [id])

这将确保仅在修改 id 后才会重新运行效果

清理功能 −清理函数用于在使用订阅函数和定时器函数过程中进行清理工作,如下所示 −

const [time, setTime] = useState(new Date())
useEffect(() => {
   let interval = setInterval(() => {
      setTime(new Date())
   }, 1000)
   return () => clearInterval(interval)
}, [time])

让我们创建一个完整的应用程序来了解后面部分的清理功能。

effect hook 的功能

effect hook 的一些显著功能如下 −

  • React 允许在一个函数组件中使用多个 effect hook。这将帮助我们为每个副作用编写一个函数并将其设置为单独的效果。

  • 每个 hook 将按照声明的顺序运行。开发人员应确保正确声明效果的顺序。

  • 依赖项功能可用于提高性能和正确执行副作用。

  • 清理功能可防止内存泄漏和不必要的事件触发。

使用效果获取数据

让我们创建一个应用程序,它将从外部源获取数据并使用本节中的 useEffect Hooks(钩子)对其进行渲染。

首先,创建一个新的 React 应用程序并使用以下命令启动它。

create-react-app myapp
cd myapp
npm start

接下来,在组件文件夹 (src/components/NameList.js) 下创建一个 React 组件 NameList

function NameList() {
   return <div>names</div>
}
export default NameList

此处,NameList 组件的目的是展示常见名称的流行列表

接下来,更新根组件 App.js 以使用新创建的 NameList 组件。

import NameList from "./components/NameList";
function App() {
   return (
      <div style={{ padding: "5px"}}>
         <NameList />
      </div>
   );
}
export default App;

接下来,创建一个 json 文件 names.json (public/json/names.json),并以 json 格式存储流行名称,如下所示。

[
   {
      "id": 1,
      "name": "Liam"
   },
   {
      "id": 2,
      "name": "Olivia"
   },
   {
      "id": 3,
      "name": "Noah"
   },
   {
      "id": 4,
      "name": "Emma"
   },
   {
      "id": 5,
      "name": "Oliver"
   },
   {
      "id": 6,
      "name": "Charlotte"
   },
   {
      "id": 7,
      "name": "Elijah"
   },
   {
      "id": 8,
      "name": "Amelia"
   },
   {
      "id": 9,
      "name": "James"
   },
   {
      "id": 10,
      "name": "Ava"
   },
   {
      "id": 11,
      "name": "William"
   },
   {
      "id": 12,
      "name": "Sophia"
   },
   {
      "id": 13,
      "name": "Benjamin"
   },
   {
      "id": 14,
      "name": "Isabella"
   },
   {
      "id": 15,
      "name": "Lucas"
   },
   {
      "id": 16,
      "name": "Mia"
   },
   {
      "id": 17,
      "name": "Henry"
   },
   {
      "id": 18,
      "name": "Evelyn"
   },
   {
      "id": 19,
      "name": "Theodore"
   },
   {
      "id": 20,
      "name": "Harper"
   }
]

接下来,创建一个新的状态变量 data,用于将热门名称存储在 NameList 组件中,如下所示 −

const [data, setData] = useState([])

接下来,创建一个新的状态变量 isLoading,用于存储加载状态,如下所示 −

const [isLoading, setLoading] = useState([])

接下来,使用 fetch 方法从 json 文件中获取热门名称,并将其设置为 useEffect Hooks(钩子)内的数据状态变量

useEffect(() => {
   setTimeout(() => {
      fetch("json/names.json")
         .then( (response) => response.json())
         .then( (json) => { console.log(json); setLoading(false); setData(json); } )
   }, 2000)
})

这里我们有,

  • 使用setTimout方法模拟加载过程。

  • 使用fetch方法获取json文件。

  • 使用json方法解析json文件。

  • 使用setData将从json文件解析的名称设置为数据状态变量。

  • 使用setLoading设置加载状态。

接下来,使用map方法渲染名称。在获取期间,显示加载状态。

<div>
   {isLoading && <span>loading...</span>}
   {!isLoading && data && <span>Popular names: </span>}
   {!isLoading && data && data.map((item) =>
      <span key={item.id}>{item.name} </span>
   )}
</div>

这里有,

  • 使用isLoading显示加载状态

  • 使用data变量显示热门名称列表

组件NameList的完整源代码如下 −

import { useState, useEffect } from "react"
function NameList() {
   const [data, setData] = useState([])
   const [isLoading, setLoading] = useState([])
   useEffect(() => {
      setTimeout(() => {
         fetch("json/names.json")
         .then( (response) => response.json())
         .then( (json) => { console.log(json); setLoading(false); setData(json); } )
      }, 2000)
   })
   return (
      <div>
         {isLoading && <span>loading...</span>}
         {!isLoading && data && <span>Popular names: </span>}
         {!isLoading && data && data.map((item) =>
            <span key={item.id}>{item.name} </span>
         )}
      </div>
   )
}
export default NameList

接下来,打开浏览器并检查应用程序。它将显示加载状态,2 秒后,它将获取 json 并显示热门名称,如下所示 −

使用 Effect 获取数据

使用 Effect 获取数据

DOM 突变

useEffect Hooks(钩子)可用于使用 DOM 及其方法来操作文档。它确保其中的代码仅在 DOM 准备就绪后才执行。让我们更改我们的姓名列表应用程序并使用 DOM 突变更新页面的标题。

首先,打开 NameList 组件并根据加载状态添加文档标题,如下所示 −

useEffect(() => {
   if(isLoading)
      document.title = "Loading popular names..."
   else
      document.title = "Popular name list"
   setTimeout(() => {
      fetch("json/names.json")
         .then( (response) => response.json())
         .then( (json) => { console.log(json); setLoading(false); setData(json);} )
   }, 2000)
})

这里我们使用了 DOM 对象 document.title 来更新页面的标题。

最后,打开浏览器,检查文​​档的标题是如何通过 DOM 操作更新的

DOM Mutations

DOM Mutations

清理函数

useEffect 可用于在从页面文档卸载组件期间删除清理函数,例如 clearIntervalremoveEventListener 等。这将防止内存泄漏并提高性能。为此,我们可以创建自己的清理函数并从 useEffect 回调参数中返回它。

让我们将名称列表应用程序更改为使用 setInterval 而不是 setTimeout,然后在卸载组件期间使用 clearInterval 删除设置的回调函数。

首先,打开 NameList 组件并更新 useEffect 部分,如下所示 −

useEffect(() => {
   if(isLoading)
      document.title = "Loading popular names..."
   else
      document.title = "Popular name list"
   let interval = setInterval(() => {
      setLoading(true)
      fetch("json/names.json")
         .then( (response) => response.json())
         .then( (json) => { console.log(json); setLoading(false); setData(json);} )
      }, 5000)
   return () => { clearInterval(interval) }
})

这里我们有,

  • 使用setImterval每5秒更新一次流行名称。

  • 在清理函数中使用clearInterval在卸载组件期间删除setInterval。

最后,打开浏览器并检查应用程序的行为。我们将看到数据每5秒更新一次。卸载组件时,将在后台调用clearInterval

总结

useEffect是函数组件的基本功能,使组件能够使用生命周期事件。它有助于函数组件提供丰富的功能以及可预测和优化的性能。