react-router-dom 有条件地构建路由并将参数传递给基于 class 的组件
react-router-dom conditionally build routes and pass parameters to class based component
我正在使用 react-router-dom
构建一个应用程序,它通过发出 AJAX 请求进行初始化,然后使用路由将参数传递给基于 class 的子组件。我不知道如何同时 1) 有条件地渲染 <Routes>
和 2) 将参数传递给子组件。
我有一个功能正常的父级 <RouterApp />
组件,以及一个有条件呈现的组件 <MyClassBasedComponent>
。
在我最初的尝试中,我这样设置我的代码:
function RouterApp() {
const preloadData = usePreloadData(); /*custom hook to make an AJAX call*/
/*Conditionally show loader screen or app content*/
if (!preloadData) {
return <WelcomeLoader />;
} else {
//build routes obj
const routesObj = {
"/": () => (props) => <About />,
"/component/:clientid": (clientID) => <MyClassBasedComponent
essentialData={preloadData}
clientID={clientID}/>,
};
return (
<Router>
<HeaderMenu />
<div className="app-body router-app">
{useRoutes(routesObj)}
</div>
</Router>
);
}
}
这会引发编译错误: React Hook "useRoutes" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?
我的下一次尝试是以字典数组形式创建一个路由对象:
function RouterApp() {
const preloadData = usePreloadData(); /*custom hook to make an AJAX call*/
/*Conditionally show loader screen or app content*/
if (!preloadData) {
return <WelcomeLoader />;
} else {
//build routes obj
const routesObj = [
{ path: "/", element: <About /> },
{ path: "/component/:clientid", "element": (clientid) => (<MyClassBasedComponent
essentialData={preloadData}
clientID={clientid}/>) },
//Various other attempts below
//{ path: "/component", element: <ClassComponentWithLink/> },
//{ path: "/component/:clientid", element: (clientid)=><ClassComponentWithLink id={clientid}/> },
//{ path: "/component/:clientid", element: <ClassComponentWithLink myProp={clientid}/> },
];
const MyRoutes = (props) => useRoutes(props.routesObj);
return (
<Router>
<HeaderMenu />
<div className="app-body router-app">
<MyRoutes
routesObj = {routesObj}
/>
</div>
</Router>
);
}
}
当我使用此表单并将函数传递给“元素”时,<MyClassBasedComponent />
不呈现。
当我使用表单 { path: "/component/:clientid", element: <MyClassBasedComponent /> },
时,组件呈现,但是当我询问它的 props 时,我在任何地方都看不到 clientid
的值。
我怎样才能正确地完成这个?
两种实现方式都不正确。在 react-router-dom@6
中不再有任何路由道具(history
、location
和 match
),并被 React hooks 取代。由于您还使用了 React class 组件,因此无法直接使用挂钩,因此您需要将 class 组件转换为函数组件,或者创建包装器组件或自定义withRouter
HOC 访问钩子并传递 along/inject 旧路由道具。我不会介绍将 class 组件转换为函数组件。
包装示例
创建一个使用 useParams
挂钩读取 clientid
路由参数并呈现 MyClassBasedComponent
组件的包装器组件。
const MyClassBasedComponentWrapper = () => {
const { clientId } = useParams();
return (
<MyClassBasedComponent
essentialData={preloadData}
clientID={clientid}
/>
);
};
然后按照预期指定路由配置。
const routesObj = [
{ path: "/", element: <About /> },
{
path: "/component/:clientid",
element: <MyClassBasedComponentWrapper />
},
];
自定义withRouter
示例
const withRouter = Component => props => {
const params = useParams();
... use the other hooks here if you need them ...
return <Component {...props} params={params} />;
};
修饰 MyClassBasedComponent
组件,使其接收 params
作为道具。
export default withRouter(MyClassBasedComponent);
然后按照预期指定路由配置。
const routesObj = [
{ path: "/", element: <About /> },
{
path: "/component/:clientid",
element: <MyClassBasedComponent />
},
];
在 MyClassBasedComponent
组件中访问 this.props.params
中的 clientId
参数。
`const { clientId } = this.props.params;
正在配置 RouterApp
组件:
const routesObj = [
{ path: "/", element: <About /> },
{
path: "/component/:clientid",
element: <MyClassBasedComponent />
},
];
function RouterApp() {
const preloadData = usePreloadData();
const routes = useRoutes(routesObj);
return !preloadData
? <WelcomeLoader />
: (
<Router>
<HeaderMenu />
<div className="app-body router-app">
{routes}
</div>
</Router>
);
};
}
我正在使用 react-router-dom
构建一个应用程序,它通过发出 AJAX 请求进行初始化,然后使用路由将参数传递给基于 class 的子组件。我不知道如何同时 1) 有条件地渲染 <Routes>
和 2) 将参数传递给子组件。
我有一个功能正常的父级 <RouterApp />
组件,以及一个有条件呈现的组件 <MyClassBasedComponent>
。
在我最初的尝试中,我这样设置我的代码:
function RouterApp() {
const preloadData = usePreloadData(); /*custom hook to make an AJAX call*/
/*Conditionally show loader screen or app content*/
if (!preloadData) {
return <WelcomeLoader />;
} else {
//build routes obj
const routesObj = {
"/": () => (props) => <About />,
"/component/:clientid": (clientID) => <MyClassBasedComponent
essentialData={preloadData}
clientID={clientID}/>,
};
return (
<Router>
<HeaderMenu />
<div className="app-body router-app">
{useRoutes(routesObj)}
</div>
</Router>
);
}
}
这会引发编译错误: React Hook "useRoutes" is called conditionally. React Hooks must be called in the exact same order in every component render. Did you accidentally call a React Hook after an early return?
我的下一次尝试是以字典数组形式创建一个路由对象:
function RouterApp() {
const preloadData = usePreloadData(); /*custom hook to make an AJAX call*/
/*Conditionally show loader screen or app content*/
if (!preloadData) {
return <WelcomeLoader />;
} else {
//build routes obj
const routesObj = [
{ path: "/", element: <About /> },
{ path: "/component/:clientid", "element": (clientid) => (<MyClassBasedComponent
essentialData={preloadData}
clientID={clientid}/>) },
//Various other attempts below
//{ path: "/component", element: <ClassComponentWithLink/> },
//{ path: "/component/:clientid", element: (clientid)=><ClassComponentWithLink id={clientid}/> },
//{ path: "/component/:clientid", element: <ClassComponentWithLink myProp={clientid}/> },
];
const MyRoutes = (props) => useRoutes(props.routesObj);
return (
<Router>
<HeaderMenu />
<div className="app-body router-app">
<MyRoutes
routesObj = {routesObj}
/>
</div>
</Router>
);
}
}
当我使用此表单并将函数传递给“元素”时,<MyClassBasedComponent />
不呈现。
当我使用表单 { path: "/component/:clientid", element: <MyClassBasedComponent /> },
时,组件呈现,但是当我询问它的 props 时,我在任何地方都看不到 clientid
的值。
我怎样才能正确地完成这个?
两种实现方式都不正确。在 react-router-dom@6
中不再有任何路由道具(history
、location
和 match
),并被 React hooks 取代。由于您还使用了 React class 组件,因此无法直接使用挂钩,因此您需要将 class 组件转换为函数组件,或者创建包装器组件或自定义withRouter
HOC 访问钩子并传递 along/inject 旧路由道具。我不会介绍将 class 组件转换为函数组件。
包装示例
创建一个使用
useParams
挂钩读取clientid
路由参数并呈现MyClassBasedComponent
组件的包装器组件。const MyClassBasedComponentWrapper = () => { const { clientId } = useParams(); return ( <MyClassBasedComponent essentialData={preloadData} clientID={clientid} /> ); };
然后按照预期指定路由配置。
const routesObj = [ { path: "/", element: <About /> }, { path: "/component/:clientid", element: <MyClassBasedComponentWrapper /> }, ];
自定义
withRouter
示例const withRouter = Component => props => { const params = useParams(); ... use the other hooks here if you need them ... return <Component {...props} params={params} />; };
修饰
MyClassBasedComponent
组件,使其接收params
作为道具。export default withRouter(MyClassBasedComponent);
然后按照预期指定路由配置。
const routesObj = [ { path: "/", element: <About /> }, { path: "/component/:clientid", element: <MyClassBasedComponent /> }, ];
在
MyClassBasedComponent
组件中访问this.props.params
中的clientId
参数。`const { clientId } = this.props.params;
正在配置 RouterApp
组件:
const routesObj = [
{ path: "/", element: <About /> },
{
path: "/component/:clientid",
element: <MyClassBasedComponent />
},
];
function RouterApp() {
const preloadData = usePreloadData();
const routes = useRoutes(routesObj);
return !preloadData
? <WelcomeLoader />
: (
<Router>
<HeaderMenu />
<div className="app-body router-app">
{routes}
</div>
</Router>
);
};
}