React(6)useEffect的基础使用

useEffect是一个React Hook函数,用于在React组件中创建不是由事件引起而是由渲染本身引起的操作,比如发送AJAX请求,更改DOM等等

import { useEffect, useState } from "react";
// 是用于组件创建不是由时间引起  而是渲染本身引起的操作 比如发送请求  
// 页面加载完成获取数据
const URL='http://geek.itheima.net/v1_0/channels'
function App() {
  const [list,setList]=useState([])
  useEffect(()=>{
   async function getList(){
      const res=await fetch(URL)
      const list=await res.json()
      console.log(list);
      setList(list.data.channels)
    }
    getList()//立即执行函数
  },[])
  return (
    <div className="App">
     <ul>
      {list.map(item=><li key={item.id}>{item.name}</li>)}
     </ul>
    </div>
  );
}

export default App;

import { useEffect, useState } from "react";
// 是用于组件创建不是由时间引起  而是渲染本身引起的操作 比如发送请求  
// 页面加载完成获取数据
// 不设置配置项时候
function App() {
  const [number,setNumber]=useState(0)
   // useEffect(()=>{
  //   console.log('组件第一次挂载和组件更新触发');
  // })
  // useEffect(()=>{
  //   console.log('空数组时候只会初始化加载');
  // },[])
  useEffect(()=>{
    console.log('初始化加载,依赖项变化');
  },[number])
  const addNum=()=>{
    setNumber(number+1)
  }
  return (
    <div className="App">
      <button onClick={addNum}>{number}</button>
    </div>
  );
}

export default App;

清除副作用的使用

子组件定时任务打印  在子组件的useEffect中进行return清除定时器

import { useEffect, useState } from "react";
function Son() {
  useEffect(() => {
    const Inter = setInterval(() => {
      console.log("定时器");
    }, 1000);

    return () => {
      clearInterval(Inter);
    };
  }, []);
  return <div>son组件</div>;
}
function App() {
  const [Show, setShow] = useState(true);

  return (
    <div className="App">
      {Show && <Son></Son>}
      <button onClick={() => setShow(false)}>卸载组件</button>
    </div>
  );
}

export default App;

<think>嗯,用户的问题是关于在ReactuseEffect使用async和await处理异步任务的最佳实践。首先,我需要回忆一下ReactuseEffect钩子的工作机制。记得useEffect的回调函数要么不返回任何内容,要么返回一个清理函数。如果直接在useEffect使用async函数,会返回一个Promise,而React并不支持这样,可能会导致警告或错误。接下来,用户提到的最佳实践,可能需要参考已有的解决方案。根据引用中的内容,比如引用[2]和[4]提到在useEffect内部定义一个异步函数然后立即调用,或者将异步函数定义在外部再调用。这两种方法都是可行的,但需要比较它们的优缺点。例如,内部定义可能更方便访问作用域内的变量,而外部定义可能更利于复用和测试。 另外,错误处理也是一个重要方面。用户可能希望知道如何处理异步操作中的错误,避免未捕获的Promise导致应用崩溃。引用[5]中的代码展示了使用try/catch来包裹异步请求,并在出错时进行相应的处理,比如显示错误信息。这应该是推荐的做法。还有,清理函数的问题。当组件卸载时,如果异步操作还在进行中,可能需要取消请求或忽略结果,防止内存泄漏。例如,使用AbortController来取消fetch请求,或者在清理函数中设置一个标志位,避免更新已卸载组件的状态。引用中没有直接提到这一点,但根据React的最佳实践,这部分需要补充。 用户可能还想知道如何优化性能,比如依赖项数组的正确使用。如果依赖项变化,需要重新执行副作用,这时候可能需要清理之前的异步任务。例如,在useEffect中返回一个清理函数,用于取消正在进行的请求。 此外,引用[3]提到了防抖优化,对于频繁触发的异步操作,可以使用防抖函数来减少请求次数。这可能是一个高级用法,但用户的问题可能更关注基础的正确使用方式,所以是否需要提及这一点需要权衡。总结一下,回答的结构应该包括:为什么不能在useEffect直接使用async、推荐的两种方法(内部定义立即执行函数或外部定义调用)、错误处理、清理机制、依赖项管理和性能优化。同时,要结合引用中的示例代码,给出具体的实现例子,并指出最佳实践的原因和注意事项。</think>### 在React useEffect中正确使用async/await的实践指南 #### 一、为什么不能直接在useEffect使用async? React的`useEffect`要求回调函数返回`undefined`或**清理函数**,而`async`函数默认返回`Promise`,会导致类型冲突。若直接写`useEffect(async () => {...})`,React会抛出警告[^1]。 --- #### 二、推荐实现方法 ##### 方法1:在useEffect内部定义异步函数并立即执行 ```javascript useEffect(() => { const fetchData = async () => { try { const response = await axios.get('/api/data'); setData(response.data); } catch (error) { console.error('请求失败:', error); } }; fetchData(); // 立即执行 }, []); // 空依赖表示只执行一次 ``` **优势**:直接访问组件作用域内的变量,逻辑集中[^4]。 ##### 方法2:外部定义异步函数后调用 ```javascript const fetchData = async () => { // ...同上 }; useEffect(() => { fetchData(); }, []); ``` **适用场景**:需复用异步逻辑时,但需通过参数传递依赖项[^2]。 --- #### 三、关键注意事项 1. **错误处理必加** 未捕获的`Promise`错误会导致React渲染崩溃,必须用`try/catch`包裹: ```javascript try { await asyncOperation(); } catch (e) { // 显示错误提示或回退UI } ``` 2. **清理未完成请求** 使用`AbortController`取消未完成的`fetch`请求: ```javascript useEffect(() => { const controller = new AbortController(); const fetchData = async () => { try { const res = await fetch('/api', { signal: controller.signal }); // ... } catch (e) {} }; return () => controller.abort(); // 清理函数 }, []); ``` 3. **依赖项管理** 若异步操作依赖props/state,需在依赖数组中声明: ```javascript useEffect(() => { const fetchUser = async (id) => { /*...*/ }; fetchUser(userId); }, [userId]); // userId变化时重新执行 ``` --- #### 四、性能优化技巧 - **防抖高频操作** 对搜索框等高频触发的场景,使用防抖函数包裹异步操作: ```javascript const search = useDebouncedCallback(async (query) => { const results = await fetchResults(query); setResults(results); }, 300); // 延迟300ms执行[^3] ``` - **避免内存泄漏** 在清理函数中设置状态标记,阻止已卸载组件的状态更新: ```javascript useEffect(() => { let isMounted = true; const fetchData = async () => { const res = await fetch(); if (isMounted) setData(res); // 仅当组件挂载时更新 }; return () => { isMounted = false }; }, []); ``` --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值