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 是每次渲染阶段后执行的函数。这对应于 componentDidMount 和 componentDidUpdate 事件

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

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

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 可用于在从页面文档卸载组件期间删除清理函数,例如 clearInterval、removeEventListener 等。这将防止内存泄漏并提高性能。为此,我们可以创建自己的清理函数并从 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是函数组件的基本功能,使组件能够使用生命周期事件。它有助于函数组件提供丰富的功能以及可预测和优化的性能。