React Router传递函数类型Props遇undefined问题求助
嘿,我完全懂你碰到的这个坑——React Router的Link组件通过URL路径传递函数类型的props根本走不通,毕竟URL只能存能序列化的数据(像字符串、数字这类),函数是没法被转成路径字符串的,这就是为啥你的decreaseIndexProject在子组件里变成undefined的原因。下面给你两个靠谱的解决方案:
你之前用的<Link to={'/Content/' + this.props.index + '/' + this.props.decreaseIndexProject}>本质是把函数直接拼进了URL路径里,但函数是引用类型,会被转成[object Function]这种无效的路径片段,React Router自然没法把它解析成有效的prop传递给子组件,所以子组件拿到的就是undefined。
Link的state属性传递函数 React Router的Link组件支持传入一个对象作为to属性,其中的state字段可以用来传递任意数据(包括函数),因为这部分数据是存在内存里的,不会被序列化到URL中。
改写你的Link组件:
<Link to={{ pathname: `/Content/${this.props.index}`, state: { decreaseIndexProject: this.props.decreaseIndexProject } }} > Page n°1 </Link>
子组件获取函数:
根据你的子组件是函数组件还是类组件,有两种写法:
- 函数组件(用
useLocation钩子):
import { useLocation } from 'react-router-dom'; function Content() { const location = useLocation(); // 加个空对象兜底,避免state不存在时报错 const { decreaseIndexProject } = location.state || {}; const handleDecrease = () => { // 调用前先判断函数是否存在,防止报错 if (decreaseIndexProject) { decreaseIndexProject(); } }; return <button onClick={handleDecrease}>Decrease Index</button>; }
- 类组件(通过
props.location):
import React from 'react'; class Content extends React.Component { handleDecrease = () => { const { decreaseIndexProject } = this.props.location.state || {}; if (decreaseIndexProject) { decreaseIndexProject(); } }; render() { return <button onClick={this.handleDecrease}>Decrease Index</button>; } }
注意点:
如果用户直接刷新子组件页面,state里的数据会丢失(因为它存储在内存中,不是URL的一部分)。如果你的场景需要刷新后依然能获取到函数,建议用下面的方案。
如果这个函数需要在多个组件间共享,或者要避免刷新丢失的问题,可以用React Context或者像Redux、Zustand这类全局状态管理工具来传递函数。
用React Context的示例:
- 创建Context:
import React, { createContext, useContext } from 'react'; // 创建Context,默认值可以设为空对象 const ProjectContext = createContext({}); // 定义Provider组件,用来传递函数 export function ProjectProvider({ children, decreaseIndexProject }) { return ( <ProjectContext.Provider value={{ decreaseIndexProject }}> {children} </ProjectContext.Provider> ); } // 自定义钩子,方便子组件获取Context export function useProjectContext() { return useContext(ProjectContext); }
- 在父组件外层包裹Provider:
import { ProjectProvider } from './ProjectContext'; // 假设这是你的父组件 class ParentComponent extends React.Component { decreaseIndexProject = () => { // 你的函数逻辑 console.log('Decreasing index...'); }; render() { return ( <ProjectProvider decreaseIndexProject={this.decreaseIndexProject}> <Link to={`/Content/${this.props.index}`}>Page n°1</Link> </ProjectProvider> ); } }
- 子组件从Context获取函数:
import { useProjectContext } from './ProjectContext'; function Content() { const { decreaseIndexProject } = useProjectContext(); return <button onClick={decreaseIndexProject}>Decrease Index</button>; }
这个方案的好处是,只要ProjectProvider在组件树中存在,子组件就能随时获取到函数,即使刷新页面也不会丢失(前提是函数的定义在Provider的上层,且页面刷新后Provider能重新渲染)。
如果用方案1,子组件的PropTypes可以这样配置:
import PropTypes from 'prop-types'; Content.propTypes = { location: PropTypes.shape({ state: PropTypes.shape({ decreaseIndexProject: PropTypes.func }) }) };
如果用方案2,子组件不需要配置这个PropTypes,因为函数是从Context获取的。
内容的提问来源于stack exchange,提问作者Guillaume

