Pushstate on React - reactjs

Is it possible to refresh the react component route on history pushState?
For ex :
<Route path="/" component={App}>
<Route path="/search/:query/" component={search}/>
</Route>
this.props.history.pushState(null,"/search/test");
Suppose if i am on the search route itself, and in my code am pushing the state,is it possible to refresh the route?

Apparently not, and it's not something the react-router maintainers are planning to support since that's not how react works (i.e. only if virtual dom changes will react reload the component). See this thread for the context of the discussion.
Angular blows everything away and reinitializes all of it. React will do a virtual DOM diff. None of your willMount, didMount etc. hooks will be called. But you'll get "already mounted" hooks like componentWillReceiveProps and componentDidUpdate.
There could be 2,000 people asking for this feature to try to reload their data, but React (not React Router) just doesn't work that way.

Related

React Router + back button is resetting my app state

I'm using React Router Dom and the BrowserRouter object to enable browser based navigation for a site I'm building. Navigation works well, but if a user hits the back button, the entirety of my App's state is wiped clean.
I'm not sure why this is happening. I've tried searching around, but all of the answers I've found don't mention why App state is getting reset.
Here's my implementation:
<BrowserRouter>
<Switch>
<Route path="/" exact render={()=><LandingPage/>}
<Route path="/about" render={()=><About/>}
</Switch>
</BrowserRouter>
Am I doing something glaringly wrong? Could anyone with experience working with React Router give me some advice? Thanks so much!
If someone like me has this problem in the future and comes here from Google, here's what's going on:
React Router doesn't store state between page loads. It just routes traffic between components and handles history, among other things.
You need a separate state management store to preserve state changes. (Redux was recommended).
Thanks #charlietfl for the info.

How to render a page to base url in react

I need to render a page for base url in react. I defined base url as,
<Router basename="/baseUrl">
<Switch>
<Route path={"/childUrl"}
</Switch>
</Router>
I am able to render page via /baseUrl/childUrl. When accessing, /baseUrl it redirects to /baseUrl/childUrl. How can I set a different page to /baseUrl
I know this is old, but in case anyone else stumbles upon this I would recommend using redux-first-router. It lets you dispatch actions either by changing the url in your browser, or the regular react way. This lets you control how components are rendered and keep the state of your application in sync with the url, without having multiple sources of truth.
Michael Sargent did a brilliant explanation, which can be found here.
And of course, you can also check out the git repo.

React router dom hijacking my image/pdf/api links

I have a react app, it uses react router dom. I built it and moved it to, say,
http://domain.tld/ the site works fine. I have two problems :
if I visit the app and then click on a pdf linked (which is just a real file on my server) react-router-dom somehow hijacks it, and shows me the 404 page I set up in react router
same goes if I try to access, for example, http://domain.tld/api/whatevs, it doesn't work either
in both case if I empty the cache, I can see my pdf, or the json result of my api then a js is injected, and a refresh gives me my 404 page.
How can I prevent react router to hijack everything ? I already have a mandatory apache rewrite to redirect in case files dont exist.
EDIT: as requested in a comment, here is how my routes are defined :
<BrowserRouter>
<div>
<Menu />
<Route path="/" exact component={Home}/>
<Route path="/pages/:page_name" component={Page}/>
<Footer />
</div>
</BrowserRouter>
I removed some routes, but the structure is intact.
EDIT2:
from what I gathered, in fact, the service worker 'hijacks' all my static server route, and that's suppose to be normal, so I'll just unregister it, but if I'm correct I can't do that unless I want my app to reload on each link, I'm still looking for a way to tell it : "pretty please, dont touch /api/, /assets/ etc"
EDIT3:
and this might just be what I need :
Setting service worker to exclude certain urls only
I'll try when I'm at work tomorrow

Remounting all react child components after root state change

I'm building a pretty large application and would like to get some insight on the best way to re-render the application based on a root component state change.
Sample Architecture
<Route path="/" component={App}>
<Route component={Layout}>
<IndexRoute component={Page} />
<Route path={page} component={Page}></Route>
...
</Route>
<Route component={Layout}>
<IndexRoute component={Page} />
<Route path={page} component={Page}></Route>
...
</Route>
In my architecture after a successful login i'm storing the users data in my App component. Every user has a client key which is used as the identifier as to which clients database/data to display. The behavior i would like to accomplish would be to update my current page with the new clients data after the a client change.
Now i could pass my data down to my components as props from my App component but i think this would be inefficient because of two reasons.
I would have to get the data for all my routes before rendering my App component.
My data would become "stale" until i re-render my App component.
Because of these reason i decided to let each page fetch it's own data using the componentWillMount life cycle hook, and passing the data down as props to the pages child components. This works for me because i'm able to fetch fresh data for each page upon navigation.
What i'm currently experiencing is that after a client change my application re-renders but since my current page has already mounted it doesn't fetch the new client data. But everything works as expected if i navigate away from the current page and then back to the page.
One solution i have in mind is to pass the users data down to each page and use the componentWillReceiveProps life cycle hook and perform a comparison check in order to fetch new data. I would like to prevent that if at all possible since my application will have 40+ pages.
Any suggestions would be greatly appreciated.
What you have mentioned about
pass the users data down to each page and use the
componentWillReceiveProps life cycle hook and perform a comparison
check in order to fetch new data.
is perfectly fine. Few examples of such a pattern in the wild:
Redux repository real world example
React Router core team recommends this method too as per issue here.

React router params change trigger firebase query

I currently have a router set up in my React app that has a link with query params:
<Router history={hashHistory}>
<Route path="/" component={Home} />
<Route path="/details/:id" component={Details} />
</Router>
What I want to do is query my firebase database when the user navigates to the details page (i.e /details/123). This code in the Details component will be:
const id = this.props.params.id;
const rootRef = firebase.database().ref();
rootRef.orderByChild("id").equalTo(id).on("child_added", function (snapshot) {
this.setState({
user: snapshot.value()
});
});
Where would I put the code that queries the firebase database? I would have thought it should not go in the render method as it does not belong there as I am setting the state - is this correct?. I have tried using the componentWillReceiveProps lifecycle function but that does not seem to get called - am I misunderstanding the lifecycles and how react-router works?
render is not the right place to put it, because there's a very strong convention that render should be pure (i.e., it shouldn't modify a component's state).
componentWillReceiveProps isn't right, either, because componentWillReceiveProps is not called when a component first mounts.
The typical place to load necessary state is from componentDidMount. (Using componentWillMount could technically work, too, but if you're doing server-side rendering, then componentWillMount will execute on the server, and dispatching AJAX or database requests from the server instead of the client can cause issues. See here.)
To be really robust, you'd also want to handle the case where the component is unmounted before your asynchronous database query finishes, because calling setState on an unmounted component will trigger a warning. The React blog has some suggested techniques for handling that.
Since you're using react-router, another option is to issue your database query from the route's onEnter event, so that the route doesn't even transition until the database query has finished. I don't have experience with this approach.

Resources