0

I have been following this answer to get redirection functionality added to a React project I have been working on.

I have a class that is currently extended by several other classes; this parent class currently extends React.Component:

class LoginForm extends Form {
   ...
}

export default LoginForm;
class Form extends React.Component {
   ...
   ...
}

export default withRouter(Form); 

This was working fine until I added this withRouter functionality on the component. I am now presented with the following error when the page loads:

Login.js:8 Uncaught TypeError: Class extends value props => {
    _s();
    const params = (0,react_router_dom__WEBPACK_IMPORTED_MODULE_2__.useParams)();
    cons...<omitted>... } is not a constructor or null
    at ./src/pages/Forms/Auth/Login.js (Login.js:8:1)

The code for wrapping the class export is:

const withRouter = Wrapper => props => {
    const params = useParams();
    const navigate = useNavigate();
 
    return (
        <Wrapper
            {...props}
            navigate={navigate}
            params={params}
        />
    )
}

export default withRouter;

What do I need to do to be able to inherit this class? I do not want to refactor the whole site to use functional components, but we are using Router V6 - and I understand that using the hook is necessary. Is there a way to inject the property higher up to make this work?

Barry Chapman
  • 6,690
  • 3
  • 36
  • 64
  • It is deprecated. You can recreate it using the hooks version: – Namwanza Ronald Nov 20 '22 at 08:01
  • In React we don't extend other React Class components ***other than*** `React.Component`. See [Composition vs Inheritance](https://reactjs.org/docs/composition-vs-inheritance.html), it's considered very anti-pattern. – Drew Reese Nov 22 '22 at 10:13

2 Answers2

0

The only way to be able to extend something wrapped with a withSomething is for withSomething to return a class component.

Because of this, you won't be able to use any useSomething hooks in your withSomething function.

Without refactoring anything significantly, you should inherit from the base class and then use withRouter on your inherited class.

Alternatively, you could go back to React Router v5 and use their withRouter HOC

Samathingamajig
  • 11,839
  • 3
  • 12
  • 34
0

The code for wrapping the class export is deprecated. You can recreate it using the hooks version like this:

import {
  useLocation,
  useNavigate,
  useParams
} from "react-router-dom";

function withRouter(Component) {
  function ComponentWithRouterProp(props) {
    let location = useLocation();
    let navigate = useNavigate();
    let params = useParams();
    return (
      <Component
        {...props}
        router={{ location, navigate, params }}
      />
    );
  }

  return ComponentWithRouterProp;
}

Or it can be written with an arrow function as you want it:

import {
  useLocation,
  useNavigate,
  useParams
} from "react-router-dom";

const withRouter = (Component) => {
  const ComponentWithRouterProp => (props) => {
    let location = useLocation();
    let navigate = useNavigate();
    let params = useParams();
    return (
      <Component
        {...props}
        router={{ location, navigate, params }}
      />
    );
  }

  return ComponentWithRouterProp;
}

For more details, check here

And finally,import your form component into loginForm eg import Form from './Form' into your LoginForm class component instead

Change your LoginForm code to something like:

import Form from './Form'
class LoginForm extends React.Component {
   ...
   // do something in your parent class
   <Form />

}

export default LoginForm;

and hence you should consider managing states as well.

Namwanza Ronald
  • 150
  • 1
  • 1
  • 12
  • And you will still just default export the `withRouter` function, right? – Barry Chapman Nov 20 '22 at 08:09
  • When implementing this method, I received this error: `Warning: The component appears to have a render method, but doesn't extend React.Component. This is likely to cause errors. Change LoginForm to extend React.Component instead.` – Barry Chapman Nov 20 '22 at 08:10
  • For the withRouter function is enough to get your routes to work. The warning says it all, you need to change your LoginForm to extend React.Component, check that your LoginForm class extends React.Component for it to work. – Namwanza Ronald Nov 20 '22 at 08:12
  • LoginForm extends Form, and then i have another component called `Form` that extends `React.Component` – Barry Chapman Nov 20 '22 at 08:14
  • You are doing it wrongly, you need to pass your states/props from one component to other eg LoginForm should receive props/states from the Form Component. Change class `LoginForm extends Form { ... }` to `class LoginForm extends React.Component { .. }` and just pass props/states from the Form component to the LoginForm. – Namwanza Ronald Nov 20 '22 at 08:26
  • Here is another example you can look at if you're not sure how to pass states from one component to another https://reactjs.org/docs/forms.html, https://reactjs.org/docs/lifting-state-up.html and https://reactjs.org/docs/composition-vs-inheritance.html. If you would prefer to manage states so easily, then, I would recommend using **redux**, a working example is here to get you started https://codesandbox.io/s/4xyi0 – Namwanza Ronald Nov 20 '22 at 08:37
  • Namwanza: LoginForm extends Form, so when I create an instance of LoginForm, it will be a child of Form, and can therefore inherit the properties – Barry Chapman Nov 21 '22 at 06:35