javascriptreactjsreact-routing

Routing doesn't read id


I have this class:

export default class Panel extends PureComponent {
    constructor(props){
        super(props);
        this.state = {
            loading: true,
            url: '/' +this.props.lang+ '/panel',
            about: '/' +this.props.lang+ '/panel' + '/about',
            user: '/' +this.props.lang+ '/panel' + '/user/1',
            userPath: '/' +this.props.lang+ '/panel' + '/user/:id'
        }


    }
    componentDidMount(){
        this.setState({
            loading: false
        });
        console.log(this.state.user);
    }

    onResize(width){
        var totalWidth  = width + 250 + "px";
        var contentWidth  = width + "px";
        document.querySelector('.panel__slideContainer').style.width = totalWidth;
        document.querySelector('.mainContainer').style.width = contentWidth;

    }
    render() {
        if(this.state.loading === true){
            return <p>Loading...</p>
        }
        return (

            <div className="container panel__container">
            <Router>

                <ReactResizeDetector handleWidth onResize={this.onResize} />
                <div className="panel__slideContainer">

                <nav className="panel__sideMenu">

                    <ul>
                        <li>
                             <NavLink exact activeClassName="active" to={this.state.url}>Home</NavLink>
                        </li>
                        <li>
                            <NavLink activeClassName="active" to={this.state.about}><Trans>change password</Trans></NavLink>

                        </li>
                        <li>
                            <NavLink  activeClassName="active" to="/pl/panel/user/1">User</NavLink>
                        </li>
                    </ul>
                </nav>
                <div className="mainContainer">
                    <Nav />
                <div>
                    <Switch>
                        <Route exact path={this.state.url}>
                            <Home />
                        </Route>
                        <Route path={this.state.about} >
                            <About />
                        </Route>
                        <Route path="/pl/panel/user/:id">
                            <User />
                        </Route>
                    </Switch>
                </div>
        </div>
            </div>
            </Router>
            </div>
          );
    }
}

I have a problem with User component which not read a props. Before I tried display route without <Switch> like this:

<Route path="" component={} />

and after click component was loaded correctly and display props but after refresh website it display me error 404. After implement Switch, it absolutely broken. Nothing display (only error with console log)

// This is the error:
> Cannot read property 'params' of undefined
> backend.js:6 The above error occurred in the <User> component:
> Uncaught TypeError: Cannot read property 'params' of undefined

@Edit User component import React from 'react';

const User = (props) => {
  return (
    <div>
<p>User id: {props.match.params.id}</p>
    </div>
  );
}

export default User;

Any idea how I can solve my problem?


Solution

  • This error is caused by the match prop being undefined in the <User/> component, when the "/pl/panel/user/:id" route is matched which in turn means an exception is thrown when params.id is accessed.

    There are a few solutions to resolve this - a simple fix is to specify the User component at it's particular <Route/> via the component prop:

    <Route path="/pl/panel/user/:id" component={User} />
    

    By specifying the User component in this way, react-router will automatically inject the match prop into User when the route is matched and the component is renderered.

    Another option is to use the withRouter:

    import { withRouter } from "react-router-dom";
    
    /* Your current User component left as is */
    const User = (props) => { ... }
    
    /* Router injected into User */
    const UserWithRouter = withRouter(User);
    
    <Route path="/pl/panel/user/:id">
        {/* Use UserWithRouter instead, match will now be defined in User */}
        <UserWithRouter />
    </Route>
    

    The withRouter HOC has the same effect as the first approach, causing the match prop to be injected into the target component (ie User) when the UserWithRouter component is rendered.

    Update

    The 404 error that you're seeing when refreshing the browser is likely due to inconsistent client side and server side routing.

    For example, navigating to a route /pl/panel/user/1 on the client and then refreshing the page will issue a request to your server for the resource at /pl/panel/user/1. Because the server doesn't know how to handle that, a 404 will typically be returned.

    A simple fix would be to replace <BrowserRouter> with <HashRouter> in your client side code. This will prefix your url path with an #, however it will allow the reloading behavior you require without the need for any changes to your backend.

    Hope that helps!