我正在更新一个Reaction项目的包,该包已经用react-router-dom v5实现了.我已经把react-router-dom更新到v6了.我在很多components中使用了this.props.history,因此我不需要更改它的 struct ,所以我决定创建一个具有该功能的包装器,并将组件作为props 传递给它,这样就不会更改太多代码.包装是这样的:

import * as React from 'react';
import { useLocation, useNavigate, useNavigationType, useParams } from "react-router";

export function withRouter(Child) {
  return (props) => {
    const [callBack,setCallBack] = React.useState();
    const location = useLocation();
    const navigate = useNavigate();
    const action = useNavigationType();
    const params = useParams();
    const match = {
      params: params
    }
    const history = {
      push: (url, onMount) => {
        if (onMount)
          setTimeout(() => navigate(url), 100)
        else
          navigate(url);

      },
      listen: (callback) => {
        setCallBack(callback);
      }
    }
    React.useEffect(() => {
      if (callBack) {
        callBack(location,action)
      }
    }, [location])

    return <Child {...props} history={history} location={location} match={match} />;
  }
}

我在如下所示的组件中使用了包装器:

function action(params) {
    return (
        <Layout {...params}>
            <PageInfo title={Utils.i18n('notificationList', true)} icon="ti-bell"/>
            <NotificationList {...params}/>
        </Layout>
    )
}

export default withRouter(action);

下面是包装组件的componentDidMount上的listen函数:

componentDidMount(): void {
        this.props.history.listen((location, action) => {
            const urlSearchParams = new URLSearchParams(window.location.search);
            const params = Object.fromEntries(urlSearchParams.entries());
            if (params.id) {
                this.setState({id:params.id})
            }
        });
        this.getNotification();
        Utils.scrollToTop();
 }

我在这次更新中遇到的问题是react-router-dom v5中存在的listen个功能.因为在Childprops 中的任何状态更改之后,所有状态都被清除,所以callBack总是未定义的,并且我不能在我的wrapper中实现listen功能.在这部分代码中,回调始终未定义:

 React.useEffect(() => {
      if (callBack) {
        callBack(location,action)
      }
    }, [location])

有谁有办法在我的包装器中实现listen个功能?

推荐答案

我在这里看到的唯一明显问题是缺少useEffect个依赖项.callbackaction都失踪了.

React.useEffect(() => {
  if (callback) {
    callback(location, action);
  }
}, [action, callback, location]);

更隐蔽的问题是通过setState updater函数将函数保存到REACTIVE状态.SetState函数接受更新状态的值100,回调函数传递前一个状态值,并期望返回下一个状态值.如果要将回调函数保存到状态,则需要使用回调函数语法并返回要保存到状态的回调函数.

listen: (callback) => {
  setCallback(() => callback); // not setCallback(callback)
}

完整代码:

export const withRouter = Component => props => {
  const [callback, setCallback] = React.useState();
  const location = useLocation();
  const navigate = useNavigate();
  const action = useNavigationType();
  const params = useParams();

  const match = { params };

  const history = {
    push: (url, onMount) => {
      if (onMount) {
        setTimeout(() => navigate(url), 100);
      } else {
        navigate(url);
      }
    },
    listen: (callback) => {
      setCallback(() => callback);
    }
  }

  React.useEffect(() => {
    if (callback) {
      callback(location, action);
    }
  }, [action, callback, location]);

  return <Component {...props} {...{ history, location, match }} />;
};

Reactjs相关问答推荐

React onKeyUp不一致地使用快速Shift+键按压

sourceBuffer. appendBuffer成功,但h5视频播放器卡住了

Next.js-图像组件加载问题

在Next.js中实现动态更改的服务器组件

如何使数据库数据在第一次呈现时显示?

使用下一步中的路由/导航不会立即加载路由

无法在主组件的返回语句中呈现预期组件

TanStack/Reaction-Query在我的Vercel应用程序中不起作用

如何在REACTIVE js中动态添加或删除输入字段?

在 Nextjs13 应用程序目录中呈现从 supabase 获取的数据

Formik onChange() 字段挂钩覆盖显示值和 Select 机制

在 React 中使用复选框管理状态

react - 警告:列表中的每个子元素都应该有一个独特的 keys props ,即使我已经设置了 keys

需要在窗口调整大小时更新 React 组件

使用 react-router-dom 时弹出空白页面

在 Remix 中使用 chartjs 和 react-chartjs-2 会出现错误react-chartjs-2未在您的 node_modules 中找到

如何使用 cypress 获取 MUI TextField 的输入值?

是什么导致了这个令人惊讶的数组导致 React

用 scss 覆盖 MUI

为什么重新渲染不会影响 setTimeout 的计数?