I recently started using react-redux to build my front-end app, but while I wrote components, I felt confused on props and states.
For example:
content
, type
changeContent
, changeType
, fetchResult
.fetched_result
.The structure of component:
<Layout>
<Header/>
<SearchContent />
<SearchType />
<SearchButton /> -> call axios to get result
<View />
<Chart />
Current Layout.js defines all functions.
changeContent(e) {
this.setState({"content": e.target.value,});
}
changeType(e) {
this.setState({"type": e.target.value,});
}
fetchResult() {
this.props.dispatch(fetchResultAction(this.state.content, this.state.type)).then(()=>{...});
}
And I passed all state
and props
into each components.
<Header
changeType={this.changeType.bind(this)}
changeContent={this.changeContent.bind(this)}
fetchResult={this.fetchResult.bind(this)}
/>
<SearchContent
changeContent={this.props.changeContent}
/>
<SearchType
changeType={this.props.changeType}
/>
<SearchButton
fetchResult={this.props.fetchResult}
/>
<View
type={this.state.type}
result={this.props.fetched_result}
/>
For sure, every components works well. However, all codes related state are written in Layout.
In this simple case, it is fine if I define fetchResult with arguments:
//this can be defined in any component
fetchResult(content, type) {
this.props.dispatch(fetchResultAction(content, type).then(()=>{...});
const { fetched_result } = this.props;
//I need to define a new "changeResult" function and "result" state in Layout
this.changeResult(fetched_result); //pass result back to layout state
}
Then I can use this function in any component with passing state.
However, the real app have lot components with complex relations. I faced a lot of coupling problems while I split layout function into below components.
For example, fetchResult
uses state searched
.
//this is defined in Layout
fetchResult() {
this.props.dispatch(fetchResultAction(this.state.content, this.state.type).then(()=>{
if(this.state.searched==false){
this.setState({"searched": true});
}
});
}
If I still do the second way, I may need to define and pass more states and changeXXX functions into components.
I hope someone can give me some best practice of props/state in reactjs.
state
and changeState
in the outermost components, and defining related function in each inner component.all state related function
in the outermost components, and passing to inner components as props. Well by looking your code it's look correct. In my experience I would suggest some pattern that you can follow for building the complex application in react-redux.
Here are few suggestion that you can follow into your application.
1. Always create Dummy component and Container components.
Dummy Component : Component which are very reusable eg. textbox can be a dummy component. In your case search button, header, can be a dummy component. These component should be pure and should not contain any action logic. These component always get data as a props from container component. In this component we should use callback handler eg textbox will have onchange method that will pass the value to the container component.
Container component : Component which can contain multiple dummy component and another container as well. All the Action logic will be place inside the container component. eg. Forms, In your case its Layout page(I would suggest you should create separate container component and put that container component inside layout).
Note : Container component should be directly bind with redux state.
Container component should use action creator to pass the required value for API call or for update the redux state.
2. Action Creator : Always keep action creator into separate file. these action method should be responsible for ajax call, redux state management. eg. user form should have separate action creator file which will have (Add, Edit, Delete method for the form). It will also help you to maintain the complex scenario as well as you container will be clean.
Note : If action method are very reusable then you can keep that method at some common place.
Suggestion : You should keep all the heavy logic in the action creator. (It will help you to have minimum logic inside the container and your container will be clean).
eg. If you want to save the user form and while saving you want to show the spinner and after save you want to show some message and then some other operation then you can put all the action inside one function
export function Save() {
return function (dispatch, getStore) {
dispatch({ type: START_SPINNER, data: true })
axiosRequest(dispatch, req1).then(function (data) {
dispatch({ type: STOP_SPINNER, data: true })
dispatch({ type: SHOW_SUCESSMESAGE, data: 'SAVED SUCCESSFULLY' });
dispatch({type: CLOSE_FORM, data: {close:true})
})
}
}
4. If you need to pass multiple props inside the component use {...props} ES6 way to pass it instead of manually passing the each property.
5. Your reducer should be very plane. Only it should contain the update logic for redux state.
6. Use redux state more instead of react state for maintaining the global data(those data which can be used across the multiple page).
You can find more information here
http://redux.js.org/docs/basics/ExampleTodoList.html
https://www.codementor.io/reactjs/tutorial/intro-to-react-redux-pros
If you will explore, there are multiple libraries where you can find the coding style.