Amber Johnson
Amber Johnson

Reputation: 65

Passing values to component using history

When I try to navigate from one component to another page using routes and need to pass some parameters across with it. I have tried providing them as state using history.push(..) as seen below but it doesn't work, both state and props are empty.

In the holder component, Holder.js

At top:

import history from '../routes/history';

In render function

<Button variant="contained" onClick={() => { history.push('/share', {
            account: this.props.account, credential: JSON.stringify(this.state.credentialInfo)});
            window.location.reload();}} fullWidth  sx={{mt: 3, mb: 2}}>Share ID</Button>

In index.js

ReactDOM.render(
<BrowserRouter>
    <Routes>
        <Route path="/" element={<App />} />
        <Route path="/share" element={<SharePage  />} />
    </Routes>
</BrowserRouter>,
document.getElementById('root')
);

In history.js

 import { createBrowserHistory as history} from 'history';

 export default history();

Upvotes: 1

Views: 394

Answers (2)

Drew Reese
Drew Reese

Reputation: 202836

It appears you are using react-router-dom version 6. In RRDv6 imperative navigation is accomplished via a navigate function returned from the useNavigate hook. The issue is that the RRDv6 BrowserRouter component instantiates and maintains its own internal history object and state. You can create your own, but since it's a separate history context it won't work with your router, routing, and navigation.

useNavigate

declare function useNavigate(): NavigateFunction;

interface NavigateFunction {
  (
    to: To,
    options?: { replace?: boolean; state?: any }
  ): void;
  (delta: number): void;
}

Import the useNavigate hook and access the navigate function, sending along state with the route transition. Route state is part of the options object as the second parameter to the navigate function.

This is only validly used in function components though, and the component using the button appears to be a class component. You can either convert the class component to a function component or create your own custom withNavigation Higher Order Component so the navigate function can be injected as props.

import { useNavigate } from 'react-router-dom';

const withNavigation = Component => props => {
  const navigate = useNavigate();
  return <Component {...props} navigate={navigate} />;
};

export default withNavigation;

Import the new HOC and decorate your class component, accessing the navigate function from props.

import withNavigation from '../withNavigation';

...

<Button
  variant="contained"
  onClick={() => {
    this.props.navigate(
      '/share',
      {
        state: {
          account: this.props.account,
          credential: JSON.stringify(this.state.credentialInfo),
        }
      },
    );
  }}
  fullWidth
  sx={{ mt: 3, mb: 2 }}
>
  Share ID
</Button>

...

export default withNavigation(MyClassComponent);

Route state is accessed the same way in v6 as it was in v5, save for the location object being a prop. Use the useLocation hook to access the location object and its state property.

useLocation

const { state } = useLocation();

...

const { account, credential } = state || {};

If SharePage is another class component then you can expand your withNavigation HOC to include other RRD hooks and inject other props.

Upvotes: 1

Anh Le
Anh Le

Reputation: 290

No. you can only:

import { useHistory } from 'react-router-dom';


function YourComponent() {
   const history = useHistory();

   const share = useCallback(() => {
    history.push(`/share?account=${this.props.account}&credential=${JSON.stringify(this.state.credentialInfo)}`);
   }, []);

   return (
      <Button variant="contained" onClick={share}>Share ID</Button>
    )
}
`

Upvotes: 0

Related Questions