Search code examples
javascriptreactjstypescriptreact-router-dom

How to use react-router-dom v5 render props using Typscript


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;

but I got error at this part enter image description here

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?


Solution

  • The Header component isn't actually consuming any props:

    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>
      );
    }