I do have a React component that loads when user clicks on a ReactRouter Link such as http://mysite/page/:id.
Inside the ComponentDidMount method I'm using the 2 following actions:
postsSetPage(page)
should be a SYNC action that changes the page right away in the store).
I'm passing it the id given from ReactRouter as page.
postsFetch(args):
is an ASYNC action that fetches data from API.
So my code looks like this:
componentDidMount() {
this.props.postsSetPage(this.props.match.params.id);
console.log(this.props.posts.query); // <========== this will not be updated
this.props.postsFetch(this.props.posts.query);
}
this.props.posts.query contains all arguments to apply filter/ordering/pagination on my API. It looks like this:
this.props.posts == {
records: [],
query: {
page: 1,
arg1: "asdasd",
argN: "blabla",
},
}
THE QUESTION:
The code inside componentDidMount doesn't work because after I set the page this.props.posts.query hasn't updated yet (console.log is confirming) and when I call fetch action query doesn't contain the correct page.
So aren't actions such as setPage suppose to be sync?
All help will be greatly appreciated!
setPage as a redux action is synchronous, but the resulting setState which happens due to change in redux store might not be (it's better to assume setState is never synchronous).
And if your setPage action goes through a middleware which does some async stuff (fetching data from api) and then forwarding the action, then the action itself wont' lead to setState call synchronously, because redux store would only change once the api data comes back.
But i guess you are facing the first problem.
One way to take care of your problem can be to do the fetch in either the action (thunked), or do it in a middleware.
As per React, this.props are the immutable object means you can not update it programmatically.
Here you will have to use this.state
Related
I am new to React and want to understand the difference from classic MVC.
I want to create a simple components that loads some data initially and renders let say a grid.
On some state or prop change it will reload the data and re-render.
What is the best approach in react from below two options?
using the lifecycle events to load the data, update some state and render while in another event will show some loading opacity.
Work with redux and react-redux? but in all example I cant see API calls.
Is this the role of a middleware (Thunk?)?
Will appropriate an explanation.
Both the approaches are correct. It depends on your use case. If you can avoid using redux in your app, use the lifecycle methods to make API calls (also called subscriptions in react documentation). If you think your app has many components and different components needs to share a state, then use redux.
You should also look at React hooks https://reactjs.org/docs/hooks-reference.html
You can use Effect Hook https://reactjs.org/docs/hooks-effect.html to make API calls and update your component's state.
Update:
Both Thunk and Sage are used to manage side effects in your application (making API calls from here). I've used saga, I don't know much about thunk.
How you would use redux-saga:
Say if you want to get some data for display on a button click, this is how it works:
On button click you dispatch an action, say GET_DATA
Your redux reducer will change some state on this particular action, say isLoading=true
You can use isLoading in your component to show a spinner/overlay
At the same time saga will listen to GET_DATA action and make the API call
If success, from Saga you'll dispatch an action, say GET_DATA_SUCCESS with the data from API call
Reducer will change isLoading=false and set the data in state, say apiData = { ... }
If failure, from Saga you'll dispatch an action, say GET_DATA_FAILED with the error code/message
Reducer will change isLoading=false and set the error in state, say apiError = { ... }
You can now use isLoading=false in you component to remove spinner and display the data (apiData) or error (apiError) in you component.
You can go through this tutorial to learn more https://redux-saga.js.org/docs/introduction/BeginnerTutorial.html
What's the correct way to set the state after a redux action is called? Before I used to do it using the componentWillReceiveProps but now as I read, it's considered legacy and should be avoided. The question is, how should I set the state without this method?
I'll give you an example:
componentDidMount() {
this.props.getProfile();
}
Let's say I call this getProfile action in componentDidMount() and as a result I get a profile object which among other things, contains a simple string field, let's say color: "red".
Based on this color field that I got from calling getProfile(), I want to setState and call another redux action without performing any click action or anything. I want to call this.props.getFavoriteColor(this.state.color)
What's the best practice?
static getDerivedStateFromProps(nextProps, prevState)
The new function which main responsibility is ensuring that the state and props are in sync for when it is required. It’s main job is replacing componentWillReceiveProps
checkout the docus: https://reactjs.org/docs/react-component.html#unsafe_componentwillreceiveprops
I would do something like below:
async componentDidMount() {
const {color} = await this.props.getProfile();
this.props.getFavoriteColor(color)
}
I am working on my first React Redux project.
The project depends on a server to get its data and therefore there is also a server API that needs to be called in order to get those data.
My question is about initialising state.
There are 2 ways I can think of initialising state:
1.) First pass an empty object {} as the initialised state of the Redux store then inside componentDidMount that is where I call the API to access the data in the server and then update the state of the store/app then.
2.) In the reducer of the Redux app call all relevant server method (e.g. getCategories(), getPosts(), etc.) then compose a object with all of the data e.g. {categories: categories, posts: posts} then pass this object to the reducer as the initial state.
Which way is the recommended way for Redux when dealing with data stored in the server?
If there is a 3rd or 4th way that is the Redux way or the recommended way then please share your knowledge. Thank you.
The way I work with data coming from the back end, and as far as I know is also the suggested way, is this:
In the componentDidMount method call a thunk action creator. you can read more about them in this link.
Inside that thunk action creator you first dispatch a REQUEST action, then perform a fetch to access the back end and when the response arrives you handle it on either the success or error handlers. Depending on the handler executed you dispatch either a SUCCESS or an ERROR action (and you attach to it all the relevant information that is coming from the back end so the reducer can access it).
In your reducer you write code to handle all the above actions (REQUEST, SUCCESS and ERROR). Each handler will transition your state, for instance the REQUEST can set an isFetching flag to true that will let you show a spinner in the UI, and the SUCCESS can set that flag to false and populate the state with the data coming from the back end and passed to the reducer using the action dispatched.
Once your reducer is updated, you will access that updated state from the UI, for instance using the connect react-redux function.
Regarding the initial state, it should represent a default state. for instance, it will have the isFetching flag in false and, if you are fetching a list of foods from the back end, then that list could be an empty list in your initial state. This is just a for instance of course. You need to set an initial state that makes sense to your app.
I hope this helps you.
The first way is the better way of initializing state. Your component makes the necessary API calls in componentDidMount and passes the data to Redux as payload of actions which the reducers use to update the state of your application.
The second way is not advisable. According to the Redux docs:
The reducer is a pure function that takes the previous state and an action, and returns the next state.
(previousState, action) => newState
...
It's very important that the reducer stays pure. Things you should never do inside a reducer:
Mutate its arguments;
Perform side effects like API calls and routing transitions;
Call non-pure functions, e.g. Date.now() or Math.random().
Edit:
You can also use thunk middleware and async actions to do API calls as explained in the Redux docs and #DiegoTArg's answer.
I'm working on a component in React (with Redux) that has the requirements to:
Retreive data from an API endpoint.
Display that data, with one field being editable.
If the editable field is edited, it has to update the rest of the fields and send them to a different endpoint.
I'm having trouble grasping how exactly I should implement the editing using the Redux metodology.
Here is a simplified component:
class MyComponent extends Component {
constructor(...args) {
super(...args);
this.props.dispatch(getDataFromEndpoint());
}
editField(e) {
this.props.dispatch(editFieldAction(e.target.value));
}
render() {
return (
<div>
<input type="text" defaultValue={this.props.data.editableField} onChange={this.editField} />
{
this.props.data.uneditable.map(x => {
return (
<span>{x}</span>
);
})
}
</div>
);
}
}
const mapProps = state => {
const { data } = state.endpointData;
return { data };
}
export default connect(mapProps)(MyComponent);
Note that I've written this component as an example, it might have errors, but you should get the point. Whenever this.editField is called, it should update every value in this.props.data.uneditable.
What is the correct way to do this?
In a sense these questions all boil down to: How do I wire up my component(s) to read from (and write to) Redux state. This is essentially the purpose of redux-react's connect function (which you have in the bottom of your example). You use the first parameter, mapStateToProps, to be able to read from state. You use the second parameter (that you don't have yet) - mapDispatchToProps - to provide the means to write to it. Dispatching an action is how you update Redux state.
You can simply use this.props.dispatch, but it is more idiomatic to use mapDispatchToProps, which simply provides an object where each property is a function which calls dispatch with the appropriate action creator. You might accept as a parameter for example the data which you are looking to update your store with.
What ends up happening is in your component when you want to update the state (say from an input), you use the methods you wired up with mapDispatchToProps to dispatch an action with the relevant data (the updated input value), and then write a reducer which responds to the action and updates the relevant part of your store. Redux will then trigger a re-render in your component and it will pull the updated data from the store.
Async actions are handled a bit differently of course (which is what your API calls will be), because they typically have several changes to state being spread out over time. Usually something like:
Start the API request. (Dispatch an action to..) Set a flag somewhere in your state indicating the API request is 'in transit'.
Receive the response. (Dispatch again to..) Set a flag somewhere saying the request is finished, and if it was successful, store your response data somewhere. If it was an error, store the error (or just the fact there was an error).
I would recommend redux-thunk for this purpose, since at least for me it is the easiest to understand and work with out of all the various libraries and methods to handle async with redux. Instead of dispatching an object which contains the data describing the action, you instead dispatch a function, which means you can write any kind of logic you would like, allowing you to dispatch several times for example. This makes it easy to do the steps outlined above.. simply have a function which calls your API, and in the callback (or .then() method) you dispatch an action with the result.
I'm a bit confused about the component lifecycle in React. Consider a component that loads its initial state by dispatching the action, getTodo() and updating the state of the entire app
componentDidMount() {
var _this = this;
axios.get('/api/todo').then(function(response) {
_this.props.actions.getTodo(response.data);
}).catch(function(err) {
console.log(err);
});
}
What can I use in componentWillUnmount() to prevent the memory leak? If I choose to do this, how will it be possible to update the state when I come back to the page from another page with this method?
Also, is it a better to just store the props that I need for the page as the state and updating the state instead? My concern with this approach is that it just doesn't update the state of the entire app and other components that might need the same props will have to go through the same unnecessary process, which could be avoided by using the first approach.
You should avoid doing api call in a component. React offers an interface "nothing" more.
You should dispatch an action. In fact an action creator can be used (check redux-thunk or a redux-api-middleware). Your state app must be hold by redux store, not in your interface.
You probably have a "top" component will is mount only once, it can dispatch this action (action which is able to get initial state)
I hope it will help