React Router Dom History goBack injecting state - reactjs

Is there a way to use the history hook function goBack(), in the same way, we use the Link component?
<Link to={{pathname:'/brand', state: {id}} />
Let's say I want the user to be able to go back to a previous page with an indexed table, to a precise table page. so I will first pass the index value in the Link state component, then on the way back using goBack() is there a way to pass again the state in order to redirect to that specific index?
hope it's clearer now

Related

How to force reach-router (in Gatsby) to reload the page when going to currently active route again?

I have a situation similar to the following:
<Link to="products" state={{ category: "all" }}>All Products</Link>
<Link to="products" state={{ category: "lawnmowers" }}>Lawnmowers</Link>
<Link to="products" state={{ category: "saddles" }}>Saddles</Link>
The idea is that depending on which link the users clicks, I'd filter out the products to only show that category. I'm reasonably satisfied with the ease of use of this solution and ideally wouldn't want to change it.
This works fine when I'm on a different route, e.g. I'm in /about and click the lawnmowers link, I'll get a page full of lawnmowers. However, if I'm on the /products route, clicking any other link that also leads to /products itself simply does nothing. The site doesn't refresh, the state doesn't change and Gatsby or Reach seem to be blocking this somehow.
Is there any way to circumvent or disable this behavior and somehow force Gatsby to reload/rerender the page?
React rerenders the page when props or state change.
if I'm on the /products route, clicking any other link that also leads to /products itself simply does nothing
This implies that neither props nor state change because you're on the same route?! Then you will not get a rerender. If I'm mistaken please rephrase and be more specific with your question.
One possible solution: By clicking the link you also trigger a function that changes the state. This means, you would have to move away from the concise <Link ... /> and instead implement a whole lot of state management code. But there is no way around if you filter by changing state.
Use React hooks useState for changing state and useEffect for applying the state change. Use Reach Router's navigate to trigger the state change.

React Router: Selective route props passing to children

Consider the following example:
return (
<Router>
<Route component={Table} path='/table' />
</Router>
);
Let's assume we're on the /table route the entire time.
Whenever the URL changes, the Router will re-render one of the Route components (even when the path doesn't change, see: https://github.com/ReactTraining/react-router/issues/7539).
My users like to share the URLs with each other and expect the displayed page to be more or less the same. Therefore, I need to store some information into the URL, e.g. /table?country=Narnia. The problem is, when I append or edit the search query, the child component will be re-rendered (because the search inside props.location changed), which will in turn trigger the update of its children and so on. In truth, only a part of the page needs to take into account this change inside the URL, e.g. table might apply some sort of filtering logic to the data.
What is the best way to achieve this behavior? I am talking about the likes of useSelector in Redux or Context Provider Pattern with React's Context.
Using useLocation/useMatch in nested children will also result in unwanted renders - one component might be interested in changes to parameter country, but some other might want subscribe to parameter age. useLocation would cause both to re-render when the url changes.
I am trying to avoid writing custom useEffect to control rendering of components subscribing to route changes.

Pass data from child to parent when navigating back with react router?

I know I can pass data when navigating forward with Link, Route ..
<Route
path="/release"
exact
render={() => <ManagedEventsList pages={this.state.pages} />}
/>
witten here: https://tylermcginnis.com/react-router-pass-props-to-components/
but is it possible to pass data also when browser back button was pressed?
This article show how to pass from state from child to parent without react router. Would it work with react router?
https://dev.to/zeyadetman/how-to-pass-state-between-components-in-reactjs-2pg1
With react-router-dom, no, it isn't possible to pass state with a back navigation. The history object can only send state with push or replace actions. The go actions only update the pointer to the current location in the history stack, i.e. go(-1) is equivalent to goBack().
If you need to preserve data correlated to the history stack or if you need to also "send" data during a back navigation then you'll need a library outside of react-router-dom. Redux would be a decent option, if you are already using it, to save in state either data used during navigation, or to along with doing a history.goBack() to also dispatch an action to save some "goBack" data in state to be retrieved via check on the previous page. Others like Redux Sagas or Thunks allow you to issue side-effects along with updating state. With these you could create your own goBackWithState action that saves some state in your Redux state and then issues the back navigation.
react-router-dom history

Static React Project, pass value from nav menu to component and from component to nav menu

I have a route that has a custom url append and I would like to pass a value to attach to the state of the component. Then a function within that component that I would like to pass the value of that state back up to route or rather, at least change the URL.
So, a route with a path like this...
<Route path="/exchange/:address" component={Exchange} />
and a function within that Exchange component that I would like to either pass a value up to the route and refresh the page or rather just change the URL. The URL or navigation from the route, should upon lookup pass that state value into the component to render what it needs to.
searchToken = (event) => {
this.setState({foo: event});
//pass foo to route or change URL with foo as address
}
To add, my site is static and I a using Hashrouter and will have to for the foreseeable future. Am I stuck having to use Redux? Or using some sort of hook like history? What would be the simplest solution here, I believe there are a few to my understanding.
this.props.history.push(`/exchange/${this.state.searchTokenAddress}`);
As Dileep Thomas said, I pushed through history into the searchToken function and got the intended results.

Is there a clean way to conditionally load and render different components for the same React Router route?

The use case is that I want to map the root (/) to one of two different components based on whether the user is logged in or not, and I want these two components to reside in different bundles and lazily loaded, so simply putting the login check in the render() method would not do.
I tried to use dynamic route definition with require.ensure() to lazily load the component, and it works for the first time, but after changing the login state the component doesn't get updated (even if I navigate to another route and back to / ).
I tried to force re-rendering the router by setting props on the component that contains the router, both manually and by making it a Redux connected component, and I also tried to add a listener to the Redux store and change the component state in response to login change, but in all of the attempts I got the error "You cannot change ; it will be ignored" and the component doesn't change.
My ugly solution is to have the different component loading code outside of the router, listen to the login state change and in response load the matching component and set it in the wrapping component's state, which is referenced in the render() code. Is there a clean "React-Router-ish" way to do what I want?
React Router 4 pretty much solves this as it made the route configuration part of the component rendering, so having conditional rendering is the same whether it's based on the location or on other props/state.
The closest thing to a clean "React-Router-ish" way to do that is to use the React Router Enterhooks.
An enter hook is a user-defined function that is called when a route is about to be rendered. It receives the next router state as its first argument. The replace function may be used to trigger a transition to a different URL.
So, use the onEnter(nextState, replace, callback?) attribute on your <Route />.
Called when a route is about to be entered. It provides the next router state and a function to redirect to another path. this will be the route instance that triggered the hook.
If callback is listed as a 3rd argument, this hook will run asynchronously, and the transition will block until callback is called.
The general best practice I follow is to place the auth-check flow away from your routes, and place it inside the transition events/hooks.
The usual behavior is - before the route handler actually gets rendered, check the auth, and redirect the user to another route. In your case, if you want to use the same route, but render different components - you should be able to do that using the same technique too. However, that's not a common thing (based on what I've seen), but it should be possible.
For a complete example of this approach, here's the auth-flow code example you can check. It is shared by the creators of React Router, so it looks credible to me.
PS: My answer is valid for React Router versions > 0.13.x.

Resources