React应用点击编辑/添加按钮触发额外API调用问题求助
问题分析与解决方案
原因排查
你的Home组件中,API调用放在了空依赖数组的useEffect中,理论上只会在组件首次挂载时执行一次。但点击编辑/添加按钮后触发额外API调用,大概率是以下两种情况:
- 组件重复挂载:当你通过
navigate跳转到/addUser或/editUser/:id后返回Home页面时,Home组件会重新挂载,导致useEffect再次执行,触发API请求。 - 无数据存在校验:即使Redux store中已有用户数据,每次组件挂载都会重复发起API请求并将数据重复dispatch到store中,放大了问题影响。
解决方案
方案1:通过Redux状态判断,避免重复请求
在useEffect中先检查Redux中是否已有用户数据,仅当数据为空时才发起API请求:
import React, { useEffect } from 'react' import { useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux' import { removePerson, addPerson } from '../actions/Slice'; export default function Home() { const navigate = useNavigate(); const dispatch = useDispatch(); const people = useSelector(state => state.people); useEffect(() => { // 仅当store中无数据时才发起请求 if (people.length === 0) { fetch("https://reqres.in/api/users?page=1") .then((response) => response.json()) .then((totaldata) => { const users = totaldata.data.map(user => ({ id: user.id, first: user.first_name, last: user.last_name, email: user.email })); users.forEach(user => dispatch(addPerson(user))); }) .catch((err) => { console.log(err.message); }); } }, [people, dispatch]); // 添加依赖,确保状态变化时能正确判断 // 其余原有代码保持不变 }
方案2:使用useRef标记请求状态,确保仅执行一次
如果希望无论组件是否重新挂载,API都只请求一次,可以用useRef标记请求是否已完成:
import React, { useEffect, useRef } from 'react' import { useNavigate } from 'react-router-dom'; import { useSelector, useDispatch } from 'react-redux' import { removePerson, addPerson } from '../actions/Slice'; export default function Home() { const navigate = useNavigate(); const dispatch = useDispatch(); const isApiFetched = useRef(false); // 标记是否已请求过API useEffect(() => { if (!isApiFetched.current) { fetch("https://reqres.in/api/users?page=1") .then((response) => response.json()) .then((totaldata) => { const users = totaldata.data.map(user => ({ id: user.id, first: user.first_name, last: user.last_name, email: user.email })); users.forEach(user => dispatch(addPerson(user))); isApiFetched.current = true; // 请求完成后标记为已执行 }) .catch((err) => { console.log(err.message); }); } }, [dispatch]); // 其余原有代码保持不变 }
额外优化建议
- 列表项的
key使用${pop.id}_${index}没必要,pop.id是唯一标识,直接用pop.id作为key即可,避免因索引变化导致不必要的组件重渲染:<tr key={pop.id}> - 可以把API请求逻辑封装到Redux的thunk action中,统一管理请求的loading、error状态,让组件逻辑更简洁。
内容的提问来源于stack exchange,提问作者dieskra
相关产品推荐
相关产品推荐

