Using typescript to write react-router 5

No longer advocate centralized routing! Nested routing is no longer the use of {props.children}. Each route is a React component.

react-router-dom

In the web side, you only need to import this package, because it takes a lot of things from the react router.

// @types/react-router-dom/index.d.ts
export { ...... } from 'react-router';

Then look at the common functions

HashRouter / BrowerRouter

It is understood as a routing container. The sub components wrapped in it can use their own defined routing components.

// index.tsx

import React from 'react';
import ReactDOM from 'react-dom';
import { HashRouter } from 'react-router-dom';
import App from './App';

ReactDOM.render(
    <HashRouter>
        <App />
    </HashRouter>
    , document.getElementById('root')
);

Route

Route component. When the route is matched, this location is rendered into the corresponding content.

  • Path needs matching path
  • component matches successfully rendered components
  • exact match or not
<Route path="/home" exact component={ Home } />

In this case, it will only match if the path is / home. If there is no exact attribute, then when the path is / home, both the / and / home routing components will be rendered.

Nested Route

v4 and above no longer support the way of {props.children} for nested routing, but directly put the child routing component in the position that needs to be rendered in the parent component.

// App.tsx
<div>
    <Route path="/" component={ Dashboard } />
</div>

// Dashboard.tsx
<div>
    <Header />
    <Route path="/home" component={ Home } />
    <Route path="/other" component={ Other } />
</div>

This nested routing method needs to ensure that the parent component has the same routing prefix (/) as the child component, and that the parent component does not have the exact attribute. (the purpose is to render the parent component first, and then match the child routing components defined inside the parent component)

Dynamic routing

Like other routing plug-ins, use colons to configure dynamic routes.

// Dashboard.tsx
<div>
    <Header />
    <Route path="/home" component={ Home } />
    <Route path="/other" exact component={ Other } />
    <Route path="/other/:id" component={ OtherDetail } />
</div>

/other/1 Will match /other and /other/:id These two routing components, according to the actual situation /other Routing component settings exact Attribute.

useParams Get route parameters
// @types/react-router/index.d.ts
export function useParams<Params extends { [K in keyof Params]?: string } = {}>(): { [p in keyof Params]: string };

The useParams() method returns an object, and directly taking the property TS will prompt that the property does not exist in the empty object. According to the specification of TS, an interface can be defined in the dynamic routing component to define the parameters of routing.

// OtherDetail.tsx
import React from 'react';
import { useParams } from 'react-router-dom';
interface RouteParams {
    id: string
}
export default () => {
    const params = useParams<RouteParams>();
    return (
        <div>
            //Dynamic route: {params.id}
        </div>
    )
}
props get route parameters

The props data type of routing component is RouteComponentProps

// @types/react-router/index.d.ts
export interface RouteComponentProps<Params extends { [K in keyof Params]?: string } = {}, C extends StaticContext = StaticContext, S = H.LocationState> {
    history: H.History;
    location: H.Location<S>;
    match: match<Params>;
    staticContext?: C;
}

There are many match attributes

// @types/react-router/index.d.ts
export interface match<Params extends { [K in keyof Params]?: string } = {}> {
    params: Params;
    isExact: boolean;
    path: string;
    url: string;
}

In dynamic routing / other/1, the value of props.match.url is / other/1, and the value of props.match.path is / other/:id. Getting the properties in props.match.params still tells TS which properties are available.

import React from 'react';
import { RouteComponentProps } from 'react-router-dom';
interface RouteParams {
    id: string
}
export default (props: RouteComponentProps<RouteParams>) => {
    return (
        <div>
            //Dynamic routing: {props.match.params.id}
        </div>
    )
}
useRouteMatch get route matching information

As mentioned above, we can use props to get the information related to routing, including match, params, etc. we can use props.match to get the matching information of routing. You can also use the useRouteMatch method.

// @types/react-router/index.d.ts
export function useRouteMatch<Params extends { [K in keyof Params]?: string } = {}>(
    path?: string | string[] | RouteProps,
): match<Params> | null;

Note that the return value of useRouteMatch() may be null and cannot be accessed simply in the form of match. *.

// Other.tsx
import React from 'react';
import { useRouteMatch } from 'react-router';
export default () => {
    const match = useRouteMatch();
    return (
        <div>Routing path:{ match && match.url }</div>
    )
}

useLocation and useHistory are used similarly.

Switch

Switch matches only the first routing component in the subcomponent. As mentioned earlier, without setting the exact property, / home will match / and / home routing components at the same time. Using switch can make a single match, but it is also related to the placement order.

<Switch>
    <Route path="/home" component={ Home } />
    <Route path="/" component={ Dashboard } />
</Switch>

Link

The component encapsulating the < a > label performs route jump.

<Link to="/home">to home</Link>

NavLink

Similar to the use of Link, the active class name will be added by default to the component whose current routing path matches the to property.

<NavLink to="/home">to home</NavLink>
<NavLink exact to="/other">to other</NavLink>
<NavLink to="/other/1">to other/1</NavLink>

When you click the to other/1 link, the to other link will also be added with the active class name, which is similar to the Router component, so for such navigation, you usually need to add the exact attribute.

Redirect

The to property is used for redirection, which is usually used in Switch as the processing of matching failure.

Programming route

The history object returned by useHistory() calls the push method.

Parameter passing

params

// Routing component
<Route path="/home/:id" component={ Home }/>

// Home.tsx
interface RouteParams {
    id: string
}
export default () => {
    const params = useParams<RouteParams>();
    return (
        <div>
            { params.id }
        </div>
    )
}

// Link jump
<Link to="/home/1">to home</Link>

// history jump
import { useHistory } from 'react-router-dom';
export default () => {
    const history = useHistory();
    const pushRouteParams = () => {
        history.push('/home/1')
    };
    return (
        <div>
            <Button onClick={ pushRouteParams }>to /home/1</Button>
        </div>
    );
};

state

// Routing component
<Route path="/home" component={ Home }/>

// Home.tsx
import { useLocation } from 'react-router-dom';
export default () => {
    const location = useLocation();
    return (
        <div>
            { location.state && location.state.id }
        </div>
    )
}

// Link jump
<Link to={{ pathname: '/home', state: { id: 1 } }}>to home</Link>

// history jump
history.push({ pathname: '/home', state: { id: 1 } })

query

// @types/history
export interface Location<S = LocationState> {
    pathname: Pathname;
    search: Search;
    state: S;
    hash: Hash;
    key?: LocationKey;
}

The location object has no query attribute. It should not provide this method

push and replace

// Link 
<Link to="/home" />
<Link to="/home" replace/>

// history
history.push(...)
history.replace(...)

Hook function

After v4, functions such as onEnter, onUpdate, and onLeave are no longer provided. Instead, the routing components correspond to life cycle methods such as componentDidMount, componentDidUpdate, and componentWillUnmount in React, respectively. This happens to be replaced with the new feature useEffect.

Use useEffect in the routing component to control the routing permission with history.replace()

const history = useHistory();
const state = true;
useEffect(() => {
    if (!state) {
        history.replace('/');
    }
});

It is also written as a custom Hook, which is used in multiple routing components

function useUserRole(state: boolean) {
    const history = useHistory();
    useEffect(() => {
        if (!state) {
            history.replace('/');
        }
    });
}

useUserRole(false);

Keywords: Javascript React Attribute Programming

Added by New Coder on Thu, 14 Nov 2019 11:14:41 +0200