How do I dispatch an action to reload the current route? - reactjs

I'm using React with React Router and Redux. I want to be able to dispatch an action from a component, that ends up reloading the current route. Is this possible ?
I would use browserHistory.push but the problem with this is that I'd first have to know the current route inside the component, which I don't, at least not without adding some cumbersome hacks to the component.
Any help is highly appreciated!

React-Router has a method to refresh/reload the page that you are currently.
https://github.com/reactjs/react-router/blob/v0.13.3/modules/createRouter.js#L435-L437
Router.refresh()
You just need to call it from any part on your application. I don't think that you need to create an action for that.

inside a component you can use
this.context.router.push()
config before use
Component.contextTypes = {
router: function () {
return React.PropTypes.func.isRequired;
}
};

Related

React useEffectin App.js before children component renders

In my React App.js component I execute the following code:
function App() {
const dispatch = useDispatch();
useEffect(() => {
dispatch(getAuthenticatedUser());
}, []);
This code fetches the current authenticated user by session from an API and will fill the redux store. However this code seems to run after the children of App are rendered. The children components use state variables, because this function is executed after my child components are rendered it won't work. I need this function to be called once before I render my child components within App.js, how can I achieve this?
You can't ask React to delay rendering, that's just not how React is supposed to work (unless you're using experimental features like Suspense, but you should probably learn idiomatic React first).
You normally simply tell React what to display depending on the current state/props, and React will automatically rerender as soon as something changed.
So if you have no state variable saying that the app is in a loading state, you should make one. After all, whether it is currently loading or not is intuitively part of the current "state" of the app, especially if you are on a slow connection for instance.
You could just do something like a ternary that only renders those children when these variables are available, something like:
variables ? <Children/> : <Loading/>
Suspense is a great experimental feature that could help you handle this if you're willing to be an early adopter!

How to dispatch slice reducer from a library not a React component

I'm currently building a React application based on https://github.com/react-boilerplate/react-boilerplate-cra-template.
This boilerplate, uses Redux with slices. Which works fine, as long as I want to update the state from within a React component. However, I am struggling with updating my application state from somewhere else. In my particular case I want to dispatch a logout event as soon as I get a response that I am unauthorized, basically resetting the application state.
Now this obviously can happen in any API request and therefor I don't want this to handle within the React component and rather handle it in my API library that handles API requests.
From what I've read so far, I should be able to dispatch an event by simply accessing the store. In this boilerplate the store is defined in the src/index.tsx file. So after adding the export keyword to it I thought I would be able to do this:
import { store } from 'index';
import { appActions } from 'app/slice';
console.log(store.getState());
store.dispatch(appAction.logout());
Somehow the state here is always undefined, even tho there is a state when I access it via a React component. Also the reducer called above never picks up the dispatched event. I also tried to encapsulate it with a timeount, in case this is just because the store isn't initialized yet, but that's not the case.
I'd appreciate your help :)
Please try to check the path is correct to get to the store.
After that please try again. I think your method is right.
If it is not working, please try to use the require method
require('index');
require('app/slice');
​
console.log(store.getState());
store.dispatch(appAction.logout());
​
Ok, here is how I finally made it work:
I imported the React hook of my slice into the src/app/index.tsx file
import { useAppSlice } from 'app/slice';
export function App() {
// use the React hook
useAppSlice();
return (
<BrowserRouter>
...
</BrowserRouter>
);
}
Even tho I'm not using the slice in this particular controller, it somehow "connects" with the store, so that I can use the slice from within any sub-controller or any library.

React router - calling same method outside componentDidMount

I have a React application where pages are linked using React router. The user is provided with several links. Each link is handled through the router.
All of the corresponding pages have similar logic before render function, so I used a URL parameter, a single Route path, and the same target component. The URL parameter is supposed to be passed to the backend service.
Since the target component is the same and only distinguishing factor is the URL parameter, once the component is rendered for any of the links, the lifecycle methods like componentWillMount, componentDidMount do not execute again. So, even if I click on another link whatever is the state created by the first hit, same is used for other links. REST call is within componentDidMount. Am I missing something?
<Route path="/location/:locationType" component={MapSelectedLocation}/>
MapSelectedLocation is supposed to handle several locationType and invoke REST service based on that.
The expected result is to execute the same code for different locationType. How can I achieve this?
You need to use componentDidUpdate lifecycle method to do the calculation or each props/state change. Put the check in this method and compare the prevProps and new props value.
Also this method will not get called on initial rendering
Like this:
componentDidMount() {
this.doCalculation();
}
componentDidUpdate(prevProps) {
if(this.props.match.params.locationType != prevProps.match.params.locationType) {
this.doCalculation()
}
}
doCalculation() {
// do the calculation here
}

Store state within the React Router component?

Ok, I'm pretty new to React in some ways and I am working on a simple react app that's 3 pages. I'm using react-router, partially so I can learn to use it.
On one page, I have a form that sets some state. The state obviously does not persist when you go to another route, because react-router renders a different component.
Solution #1
A solution is to have the main "App" component render one of the 3 pages/components (looking up the current route with params) and just store state there.
Solution #2
Another solution that seems obvious is storing the state in the Router component along with all the methods to update the state.
Then, I could just pass down the methods to update state to the components in the router. Seemed like a good idea, but I cannot seem to find anything online about anyone doing anything like that.
I see a lot of redux, but that's overkill for what I am doing.
So, is that possible? If it is, is there some reason that I cannot find anything about it? (Am I missing some terrible security thing or other gotchas that doing this would create.)
Instead of redux, i think you can also try react context. Ref
You can create a context in you App component and wrap your 3 page components in Context Provider to access the context. You can pass a map while creating a context, with values and setter,getter methods and use that map to change the values in your context map.
You can watch this talk for better understanding.
Hope this helps.
Redux is what you need. Check this below approach as well.
App component
class App extends Component {
state= {
test: 'test'
};
render() {
return (
<Route path="/" component={() => {<Home {...this.state.test}/>}/>
</div>
);
}
}

How to dispatch actions on location change with react router v4

I am using react-router-4.0.0-beta.4 with redux, I am trying to figure out the best way to dispatch actions on route change. I see that a few versions ago there was an API/event hook for this here. But I see that it is now gone. Trying to do the modern equivalent of what redux-router did.
Seems like the best way to dispatch an action is to do so at component's componentWillMount(), componentDidMount() or componentWillUnmount() methods.
IGNORE WHATS BELOW
There is onEnter prop. Like here comet-frontend
onEnter(nextState, replace, callback?)
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.
https://github.com/ReactTraining/react-router/blob/master/docs/API.md#onenternextstate-replace-callback
BUT, there still is onChange prop, doing exactly what you described. Maybe tell us what exactly is your issue. Because seems like you're doing something wrong.
So you have to wrap your main application component in a withRouter and react based on props changing in the props that withRouter passes down, namely the props.location.pathname for example.
You can see a discussion of how it may work here https://github.com/ReactTraining/react-router/issues/4603

Resources