preactjs / preact-router

:earth_americas: URL router for Preact.
http://npm.im/preact-router
MIT License
1.01k stars 156 forks source link

RouteProps does not match react-router's RouteProps #406

Closed mellis481 closed 2 years ago

mellis481 commented 2 years ago

I'm working to create a protected route component in my Preact app. This can be done in a React app that uses react-router like this:

import React from 'react';
import { Redirect, Route, RouteProps } from 'react-router-dom';

interface OwnProps extends RouteProps {}

export const ProtectedRoute: React.FC<OwnProps> = ({ component: Component, ...rest }) => {
  const isAuthenticated = checkIsAuthenticated();

  return (
    <Route
      render={(props) =>
        isAuthenticated && Component ? <Component {...props} /> : <Redirect to="/logout" />
      }
    />
  );
};

In react-router, RouteProps is defined like this and does not use generics or require a type to be defined:

export interface RouteProps<
    Path extends string = string,
    Params extends { [K: string]: string | undefined } = ExtractRouteParams<Path, string>
> {
    location?: H.Location;
    component?: React.ComponentType<RouteComponentProps<any>> | React.ComponentType<any>;
    render?: (props: RouteComponentProps<Params>) => React.ReactNode;
    children?: ((props: RouteChildrenProps<Params>) => React.ReactNode) | React.ReactNode;
    path?: Path | readonly Path[];
    exact?: boolean;
    sensitive?: boolean;
    strict?: boolean;
}

I'm trying to use this code to create the protected route component in my Preact app like this:

import { FunctionalComponent, h } from 'preact';
import { RouteProps } from 'preact-router';

interface OwnProps extends RouteProps { }

export const ProtectedRoute: FunctionalComponent<OwnProps> = ({ component: Component, ...rest }) => {
  const isAuthenticated = checkIsAuthenticated();

  return isAuthenticated && Component ? <Component {...rest} /> : <Redirect to="/logout" />;
};

This results in a type/compilation error because preact-router defines RouteProps like this:

export interface RouteProps<Props> extends RoutableProps {
    component: AnyComponent<Props>;
}

Why does preact-router's RouteProps not match react-router's RouteProps?

rschristian commented 2 years ago

If you reference the readme:

💁 Note: This is not a preact-compatible version of React Router. preact-router is a simple URL wiring and does no orchestration for you.

If you're looking for more complex solutions like nested routes and view composition, react-router works great with preact as long as you alias in preact/compat.

It doesn't match because it's not intended to.

Here's an example of a type-safe way to do an authenticated route:

import { FunctionalComponent, h, VNode } from 'preact';
import { useEffect } from 'preact/hooks';
import { Route, route, Router } from 'preact-router';

const AuthenticatedRoute = (props: { path: string; component: FunctionalComponent<any> }): VNode => {
    const isAuthenticated = checkIsAuthenticated();

    useEffect(() => {
        if (!isAuthenticated) route('/auth/login', true);
    }, [isAuthenticated]);

    return <Route {...props} />;
};

const App: FunctionalComponent = () => {
    return (
        <div id="app">
            <Router>
                <AuthenticatedRoute path="/" component={Home} />
            </Router>
        </div>
    );
};