Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Converting React function component to class component issue

I have the following react functional component to help support authentication required routes with react-router.

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    isAuthenticated() ? ( 
        <Component {...props}/>
    ) : (
        <Redirect to={{
            pathname: '/login', 
            state: {from: props.location }
        }}/>
    )
  )}/>
)

I need to convert this from a functional component to a class component so I can take advantage of the componentDidMount method of React.Component. Unfortunately I'm having trouble figuring out how to migrate this. If I take it as is I need to replicate the Component and ...rest parameters, but I'm not sure how to do that. I think I can get the Component parameter with this.props.component, but I'm not sure how to pull ...rest. I'm new to JSX and ES6 so any help or guidance would be much appreciated.

like image 564
Chris Dellinger Avatar asked Apr 29 '17 12:04

Chris Dellinger


People also ask

Can we use functional component in class component?

A functional component is just a plain JavaScript pure function that accepts props as an argument and returns a React element(JSX). A class component requires you to extend from React. Component and create a render function which returns a React element. There is no render method used in functional components.

Why are functional components better than class components?

Performance differenceFunctional components show a greater performance than class components. The point used to measure this is the React functional element made of a simple object with the type(string) and props(object) 2 properties. Rendering such a component needs to call the function and passing props.

Should I use class or function components React?

Although we should prefer using function components most times as React also allows using state with function components in React version 16.8 and later by using the useState hook, which is also recommended by Meta (Facebook App) itself.


2 Answers

The functional component is the render function, therefore:

class PrivateRoute extends React.Component {
    render() {
       const {component: Component, ...rest} = this.props;

       return (
           <Route {...rest} render={props => (
               isAuthenticated() ? ( 
                 <Component {...props}/>
           ) : (
            <Redirect to={{
                pathname: '/login', 
                state: {from: props.location }
            }}/>
           )
         )}/>
       );
    }
}

or, written a bit more readable:

class PrivateRoute extends React.Component {
    render() {
       const {component: Component, ...rest} = this.props;

       const renderRoute = props => {
           if (isAuthenticated()) {
              return (
                  <Component {...props} />
              );
           }

           const to = {
               pathname: '/login', 
               state: {from: props.location}
           };

           return (
               <Redirect to={to} />
           );
       }

       return (
           <Route {...rest} render={renderRoute}/>
       );
    }
}
like image 197
Sulthan Avatar answered Oct 11 '22 12:10

Sulthan


A nice, clean refactor by extending the Route component:

class PrivateRoute extends Route {

    render() {
        return isAuthenticated()
            ? super.render()
            : <Redirect to={{
                pathname: '/login',
                state: {from: props.location}
            }}/>;
    }
}

If you use this, you have to wrap your <PrivateRoute/>s in a <Switch/>, as below. Otherwise, you will have duplicate redirects and the page will fail to load.

<Router>
    <Navbar/>
    <SideDrawer/>
    <Switch>
        <Route              path="/tokens"   component={Login}/>
        <PrivateRoute exact path="/"         component={ExampleComponent}/>
        <PrivateRoute       path="/users"    component={Users}/>
        <PrivateRoute       path="/software" component={Software}/>
    </Switch>                   
</Router>
like image 28
Cameron Hudson Avatar answered Oct 11 '22 13:10

Cameron Hudson