英文:
How to use react-router-dom v5 render props using Typscript
问题
如何在Typescript中使用Route
的render
属性?
您可以在Typescript中使用Route
的render
属性,但需要为render
函数提供适当的类型定义。以下是如何做的示例:
首先,确保您的React Router版本是5.x或更高版本,因为在React Router 6中,render
属性已被移除,而是使用element
属性。
import React from 'react';
import { BrowserRouter, Route, RouteProps } from 'react-router-dom';
// 先为RouteProps类型添加一个render函数的定义
interface CustomRouteProps extends RouteProps {
render: (props: any) => React.ReactNode;
}
// 然后,创建一个自定义的Route组件,使用刚刚定义的CustomRouteProps类型
const CustomRoute: React.FC<CustomRouteProps> = ({ render, ...rest }) => {
return <Route {...rest} render={render} />;
};
// 现在,您可以在应用程序中使用CustomRoute组件了
function App() {
return (
<BrowserRouter>
<CustomRoute
path="/"
render={props => (
<>
<Header {...props} />
<Routes />
<Footer />
</>
)}
/>
</BrowserRouter>
);
}
export default App;
通过上述示例,您可以将render
属性的类型定义为接受一些props并返回React节点的函数,并且在应用程序中使用CustomRoute
组件来代替原始的Route
组件,以便能够使用render
属性。
希望这可以帮助您在Typescript中使用Route
的render
属性。如果您有任何其他问题,请随时提问。
英文:
I tried to convert a React app from Javascript to Typescript from code in youtube tutorial.
import 'swiper/swiper.min.css';
import './assets/boxicons-2.0.7/css/boxicons.min.css';
import './App.scss';
import { BrowserRouter, Route } from 'react-router-dom';
import Header from './components/header/Header';
import Footer from './components/footer/Footer';
import Routes from './config/Routes';
function App() {
return (
<BrowserRouter>
<Route
render={props => (
<>
<Header {...props} />
<Routes />
<Footer />
</>
)}
/>
</BrowserRouter>
);
}
export default App;
This is my Header code
import { useRef, useEffect } from 'react';
import { Link, useLocation } from 'react-router-dom';
import './header.scss';
import logo from '../../assets/tmovie.png';
const headerNav = [
{
display: 'Home',
path: '/'
},
{
display: 'Movies',
path: '/movie'
},
{
display: 'TV Series',
path: '/tv'
}
];
const Header = () => {
const { pathname } = useLocation();
const headerRef:any = useRef(null);
const active = headerNav.findIndex(e => e.path === pathname);
useEffect(() => {
const shrinkHeader = () => {
if (document.body.scrollTop > 100 || document.documentElement.scrollTop > 100) {
headerRef.current.classList.add('shrink');
} else {
headerRef.current.classList.remove('shrink');
}
}
window.addEventListener('scroll', shrinkHeader);
return () => {
window.removeEventListener('scroll', shrinkHeader);
};
}, []);
return (
<div ref={headerRef} className="header">
<div className="header__wrap container">
<div className="logo">
<img src={logo} alt="" />
<Link to="/">tMovies</Link>
</div>
<ul className="header__nav">
{
headerNav.map((e, i) => (
<li key={i} className={`${i === active ? 'active' : ''}`}>
<Link to={e.path}>
{e.display}
</Link>
</li>
))
}
</ul>
</div>
</div>
);
}
export default Header;
I use some package
@testing-library/jest-dom: 5.16.5
@testing-library/react: 14.0.0
@testing-library/user-event: 14.4.3
axios: 1.4.0
prop-types: 15.8.1
query-string: 8.1.0
react: 18.2.0
react-dom: 18.2.0
react-router-dom: 5.3.0
sass: 1.62.1
swiper: 6.8.4
More detail you can see my json
Here my package.json
{
"name": "dummy",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"preview": "vite preview"
},
"dependencies": {
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@testing-library/user-event": "^14.4.3",
"axios": "^1.4.0",
"prop-types": "^15.8.1",
"query-string": "^8.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^5.3.0",
"sass": "^1.62.1",
"swiper": "^6.8.4"
},
"devDependencies": {
"@types/react": "^18.0.37",
"@types/react-dom": "^18.0.11",
"@types/react-router-dom": "^5.3.3",
"@typescript-eslint/eslint-plugin": "^5.59.0",
"@typescript-eslint/parser": "^5.59.0",
"@vitejs/plugin-react": "^4.0.0",
"eslint": "^8.38.0",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.3.4",
"typescript": "^5.0.2",
"vite": "^4.3.9"
}
}
How to use Route
render
prop in Typescript?
答案1
得分: 1
`Header`组件实际上没有使用任何props:
```tsx
const Header = () => { // <-- 没有PROPS
const { pathname } = useLocation();
const headerRef:any = useRef(null);
const active = headerNav.findIndex(e => e.path === pathname);
...
Header
使用了替代了旧的路由props的React hooks,特别是useLocation
hook,用于访问先前的props.location
prop值。现在使用React hooks是首选方法。
由于没有使用props,您应该清理路由并删除传递路由props的部分。
function App() {
return (
<BrowserRouter>
<Route
render={() => (
<>
<Header />
<Routes />
<Footer />
</>
)}
/>
</BrowserRouter>
);
}
或者作为一个小的优化,直接渲染Header
、Routes
和Footer
,因为它们由一个无路径的路由渲染并且无条件地渲染。
function App() {
return (
<BrowserRouter>
<Header />
<Routes />
<Footer />
</BrowserRouter>
);
}
<details>
<summary>英文:</summary>
The `Header` component isn't actually consuming any props:
```tsx
const Header = () => { // <-- NO PROPS
const { pathname } = useLocation();
const headerRef:any = useRef(null);
const active = headerNav.findIndex(e => e.path === pathname);
...
Header
is using the React hooks that have supplanted the older route props, in this case, specifically the useLocation
hook to access what was previously the props.location
prop value. Using the React hooks is now the preferred method.
Since no props consumed you should clean up the route and remove the passing through of route props.
function App() {
return (
<BrowserRouter>
<Route
render={() => (
<>
<Header />
<Routes />
<Footer />
</>
)}
/>
</BrowserRouter>
);
}
Or as a minor optimization, render the Header
, Routes
, and Footer
directly since they are rendered by a pathless route and unconditionally rendered anyway.
function App() {
return (
<BrowserRouter>
<Header />
<Routes />
<Footer />
</BrowserRouter>
);
}
答案2
得分: 0
以下是翻译好的部分:
你不能直接将 ...props
作为属性传递到这里,因为在该文件和标头组件之间存在类型不匹配,正如错误中所提到的(history、location、match 和 staticContext)。你需要在标头组件中设置正确的类型(例如,扩展 intrinsicAttributes),如下所示:
interface HeaderProps extends React.HTMLAttributes<HTMLElement> {
history: History<unknown>;
location: Location<unknown>;
match: match<{ [x: string]: string | undefined; }>;
staticContext?: StaticContext | undefined;
}
function Header(props: HeaderProps) {
...
}
英文:
You cannot directly pass ...props
as an attribute here, because there is types mismatch between this file and header component, as mentioned in the error (history, location, match, and staticContext). You need to set the proper type in header component (e.g., extend intrinsicAttributes), as:
interface HeaderProps extends React.HTMLAttributes<HTMLElement> {
history: History<unknown>;
location: Location<unknown>;
match: match<{ [x: string]: string | undefined; }>;
staticContext?: StaticContext | undefined;
}
function Header(props: HeaderProps) {
...
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论