React组件中如何点击react-router的Link时重新加载axios获取的新数据
问题原因
当多次点击指向同一个路由的<Link>时,react-router默认会复用已存在的组件实例,不会触发组件的卸载+重新挂载流程,因此componentDidMount生命周期只会在组件首次渲染时执行一次,后续路由跳转不会重新拉取数据。
你之前写的componentDidUpdate触发无限循环的原因是:直接在钩子中调用getData,getData请求完成后调用setState会触发组件重新渲染,重新渲染后又会进入componentDidUpdate钩子,形成死循环。
解决方案
方案1:给componentDidUpdate增加触发条件(推荐)
首先确保你的List组件可以拿到路由的location属性:
- 如果是react-router v5 版本,直接用内置的
withRouter高阶组件包裹List组件即可注入路由属性 - 如果是react-router v6 版本,由于官方移除了类组件专属的
withRouter,可以自行封装一个高阶组件注入路由属性,代码如下:
import { useLocation } from 'react-router-dom'; const withRouter = (WrappedComponent) => (props) => { const location = useLocation(); return <WrappedComponent {...props} location={location} />; }; // 导出组件时包裹 export default withRouter(List);
之后修改componentDidUpdate的逻辑,只在路由发生变化或者请求地址变化时才重新拉取数据:
componentDidUpdate(prevProps) { // 路由路径变化 或 请求url变化时才触发数据拉取 if (prevProps.location.pathname !== this.props.location.pathname || prevProps.url !== this.props.url) { this.setState({ loading: true }, () => { this.getData(); }); } }
方案2:编辑操作后主动更新数据
如果你的编辑操作是在当前应用内完成的,可以在编辑提交成功后,主动触发列表组件的getData方法,或者通过全局状态管理(如Redux、Context)同步更新列表数据,不需要依赖路由跳转触发更新,性能更优。
额外优化:添加请求取消逻辑
避免组件卸载后请求返回触发无用的setState报错:
class List extends Component { constructor() { super(); this.state = { entities: [], loading: true}; // 初始化axios取消令牌 this.cancelSource = axios.CancelToken.source(); } componentDidMount() { this.getData(); } componentWillUnmount() { // 组件卸载时取消未完成的请求 this.cancelSource.cancel('组件卸载,请求终止'); } getData() { axios.get(this.props.url, { cancelToken: this.cancelSource.token }).then(response => { this.setState({ entities: response.data, loading: false}) }).catch(err => { // 忽略取消请求的报错 if (axios.isCancel(err)) return; // 其他错误处理逻辑 }) } // 其余代码省略 }
内容的提问来源于stack exchange,提问作者Bradmage
相关产品推荐
相关产品推荐

