I am somewhat new to ReactJS.
I want to store data for complicated computations in ReactJS. Since the setState is asynchronous, I cannot be bothered to store all the required data inside state as it would be next to impossible to do what I want.
I was thinking of doing the following: store the needed variables inside an object inside the state itself. E.g the state defined in the constructor is the following object
constructor(props){
this.state = { complicated_storage: { x : 123, y : 324 } }
}
This way I can manipulate this.state.compicated_storage.x or this.state.compicated_storage.y, and do stuff like this.state.compicated_storage.x = 4 without worrying about asynchronous behavior.
Is this a bad way of doing stuff in ReactJS. I noticed that with this you can bypass the entire setState mechanism, and just store all my variables inside the object within the state.
Thank You
Is this a bad way of doing stuff in ReactJS. I noticed that with this you can bypass the entire setState mechanism, and just store all my variables inside the object within the state.
The entire purpose of state is re-rendering components whenever it changes. If you modify it directly, such as state.someVariable = 2, React will not know about your change, and it will not rerender your components after the change (however, the change will be reflected if something else later causes a rerender).
If you need a change to some data trigger a rerender and update the view, use state together with setState.
If not, you can simply use a class field, rather than store it inside state.
Besides, I'm not sure in what way asynchrony you think will impede your goals, so perhaps you should be clearer there. State being asynchronous just means that changes to state are made "a little later" after the function is called (it's a whole other topic), so React can batch updates for performance reasons.
Last but not least, you should look into hooks (useState), instead of using class components.
Related
I tend to avoid using class variable as much as possible, likely 99% of my codes are done with state. Always have an impression that, we should avoid using this because React re-render UI when there are change to state or props only.
Recently my colleague started using class variable, for storing some hardcoded value like following. I don't see why we can't store this hardcoded value within state, although the value actually never gets updated in app. And this type of value assigning still works.
this.Arr = [
{ option: 'Product'},
{ option: 'Technical'},
{ option: 'Enquiry'},
{ option: 'Report'},
];
So, should we use class variable in react native? What's your supporting argument here?
Update
After some further readings from the following questions, I came into a conclusion of..
Readings:
ReactJS - What is difference between component state and class variable?
Should a React component use (fixed) values not on state or props?
Conclusion:
As always, keep variable that possibly mutate inside State Variable.
It's fine to store hardcoded value with Class Variable. However, it might make sense to move them to a constant file where you read all the fix value from there.
Using Class Variable is not an anti-pattern of ReactJS/ReactNative. Since the value does not require UI to re-render, hence storing in Class Variable is not an issue.
Appreciate anyone to comment further. Thanks.
If this variable is something that will never change and doesn't depend on anything that exists in the scope of your component, I'd suggest storing it as a constant outside of your component instead.
If you do need to generate it based on things that are in the scope of your component, you need to store it either as a state or as a class variable.
I would recommend that you store it as a state only if you need to update your UI when that variable changes (with setState). If you don't need that, it's better to store as a class variable. And the reason is that if you store it on a state, without actually requiring a UI update when that variable changes, you will end up causing unnecessary re-renders, that may be expensive.
Also, storing something that is by definition not a state, inside a state, is more confusing in my opinion than storing it separately as a class variable.
Btw, If you're working in a project that allows you to move from class components to hooks, I'd strongly suggest so.
I have built my own FormBuilder component (which is almost 5k line now), so it can cover all my needs, one issue i'm encountering is loading a new set of FormData any time the user needs, since my FormBuilder can accept a set of nested components, its kinda hard comparing the changes, and handling everything in component did mount, one easy way is building a loadFormData method inside the FormBuilder and calling this method from outside the component
I know this can easily be accomplished using ref attribute, but react highly suggest avoiding this and i got discouraged! and i was not sure if i should do this or not!
So i came up with a new alternative which kinda does the same thing:
class A {
onGetFormBuilderInternalFunction = (functions) => {
this.formBuilderFunctions = functions
}
onLoadButtonClick = () => {
this.formBuilderFunctions.loadFormData(someNewData)
}
render () {
<FormBuilder onGetInternalFunction={this.onGetFormBuilderInternalFunction}
}
}
class FormBuilder {
componentDidMount() {
if (this.props.onGetInternalFunction) {
this.props.onGetInternalFunction({
loadFormData: this.loadFormData,
})
}
}
}
So what do you think ?, is this a better approach ? or is this still a bad one ?, i was thinking using this method will at least only gives access to functions i need and not everything else.
I should also mention, loadFormData is simply one example, and there are at least a couple of these special function which i really really think is best to simply call from outside, so even if i do somehow pass the new data from props and handle it in componentDidUpdate, for the rest of these functions, i still need to access the FormBuilder
Yes that is the correct way to do it. However, if you have a 5,000 line component I would strongly suggest breaking it up into smaller sub components.
Keep state and handler functions in Parent and pass it down to FormBuilder as props.
I'm not sure how your component is set up so these are just thoughts based on a vague understanding.
Generally, you wouldn't want to do either of those approaches. Instead, the recommended approach is to pass someNewData to FormBuilder as one or more props (I'm guessing one prop, in your case).
Avoid using refs for anything that can be done declaratively.
– React Docs: When to Use Refs
This sort of scenario is discussed in Lifting State Up:
Instead of trying to sync the state between different components, you should rely on the top-down data flow.
– React Docs: Lifting State Up # Lessons Learned
If you're keeping track of changed state separate from your initial data, then you just need to reset that state when the form data (someNewData) changes. However, that's not the recommended approach.
Instead, uncontrolled components might be a great fit. By setting defaultValue to the initial data (i.e. someNewData.someField) and then letting the component deal with the value until you need it (e.g. when submit is clicked read the value from the component), you might be able to simplify your FormBuilder. Note: if you want to reset the uncontrolled component when your initial data (someNewData.someField) changes, you will need to use a key prop on the uncontrolled component with the value based someNewData.someField.
If you want to “reset” some state when a prop changes, consider either making a component fully controlled or fully uncontrolled with a key instead.
– React Docs: React Component # static getDerivedStateFromProps()
In response to your main question:
Better as you are doing right now than using ref.
I base this answer on what the react documentation says in the last paragraph of the "ref" glossary description and that the current approach can also be supported in case FormBuilder is refactored to be a functional component in the future (with Hooks and so), while using "ref" wouldn't.
I am learning Redux. As I understand, Redux in React helps us to manage state of React app. But why can't I just use empty object to hold all necessary state changes?
For example, I have root component with two subcomponents.
<App>
<Label/>
<Button/>
</App>
Inside Label I have state {numb: 1} and one function, that increase numb
increase() {
setState(prevState => {
return {numb: prevState.numb + 1}
});
}
On top of this component I import Store.js file, that exports empty object, that I use to store all my change state functions.
import Store from './Store'
And in the constructor of Label, I just assign function from that component
Store.plusOne = this.increase
That helps me to import Store file inside Button component and use increase function to increase Label's numb property.
<button onClick={Store.increase}>Plus One to Label's numb</button>
So what is the point to use Redux, if I can store any state change function in a separate object?
I had the same feeling when I started with Redux a few years ago. "Man, this seems overly complicated". But then I realised while not using redux that I was doing the same things but less efficient and more error prone when doing things "manually".
Redux comes with a few powerful helper functions. The first one is connect which helps you to get those state properties into your components. You can literally connect your components to your state. You don't have to worry about anything else, change the state in a single place and watch the changes flow through your application.
Because you "plop" (yes, a technical term...cough) all the properties you need for that component from your state onto the props of your component you automatically get that the component refreshes when your state changes. Even while using pure functions or a PureComponent which might be very good for performance.
You can see it like this. If you want React + Redux to automatically reflow your application: use Redux. If you manually want to update a object and manually force your application to reflow, use a custom state object.
That being said, I think redux makes sense in bigger applications where multiple components depend on the same state. If you just have a single piece of data rendered in a single component or a demo app with a simple button click you might as well keep it simple with a small object.
I am learning React, and trying to wrap my head around the syntax, and concepts. From the tutorials of React it is mentioned:
State Updates May Be Asynchronous
React may batch multiple setState() calls into a single update for
performance.
Because this.props and this.state may be updated asynchronously, you
should not rely on their values for calculating the next state.
My question is, if the this.state is not updated at all times, can we rely on it to show the right information? If my understanding is correct, React will update this state in batches for performance reasons, but does it affect the accuracy of the application? How does React create these batches and when do they get applied?
React uses state to help manage each piece of component with javascript. Since state can always change it makes it really flexible. One downside is that since it is flexible it can be hard to manage the state when there are multiple objects. It is ideal to keep components in manageable pieces so that you can locate when a state is not behaving as expected.
To prevent data from mutating unexpectedly, tools/concept such as ImmutableJs or Redux have been combined with React to make managing tools more efficent.
Redux controls/organizes where pieces of state changes through a one-directional flow. http://redux.js.org/docs/basics/UsageWithReact.html
ImmutableJs uses persistent immutable data structures which locks state to prevent unexpected changes. https://facebook.github.io/immutable-js/
React will render component with updated state as soon as it is reasonable - for example in event handlers you are able to change state of multiple components, however it is not reasonable to render them with new state separately - instead React will batch updates and render components after event handler finishes.
In correctly written application delay between update and render will be unnoticeable for user. From developer perspective asynchronous updates may introduce hard-to-find bugs (using Redux where every state update is based on previous state should solve most of them; this is of course possible also in pure React by using setState() with callback).
State being asynchronous does not mean that you can't rely on it, but you should be careful how and when you are using the information you are keeping there.
For example:
this.setState({charCount: 5});
console.log(this.state.charCount) // may not be 5 as setState is asynchronous
On the other hand you can use callback to be sure that you got a correct value:
this.setState({charCount: 5}, () => { console.log(this.state.charCount) });
General practice is that you should try to minimize the use of state and only use it, when changes are needed on user interface. If you need to process or manipulate data without UI changes try to avoid using state and use for example this practice: Lifting State Up
I am writing a complex react app and using Cortex as my central model. The philosophy with cortex is that it wraps your data and on changing the data, calls a complete re-render from the root. This works great especially when you have non hierarchical views changing state and affecting the other.
The issue that I am facing is maintaining states/props on re-render. For example I have a certain hierarchy which goes like this:
<Page>
<EditorCard>
<Editor/>
<PublishButton/>
</EditorCard>
</Page>
The EditorCard needs the JavaScript instance of the Editor in order to make changes to the Editor on clicking the PublishButton (I am using an external library inside Editor which exposes methods for editing). Hence the Editor on ComponentDidMount sets the instance as a prop on the EditorCard by calling a function passed down to it.
My issue is that when I click the PublishButton I change the value of the cortex object which causes a re-render from the root and I loose the props for that Editor (since component is already mounted ComponentDidMount is not called again).
The way I took care of this problem is by caching of getDefaultProps.
Inside EditorCard my default props are:
getDefaultProps: function() {
return {
cachedData: {},
}
},
And is saving the editor instance as this.props.cachedData.editor = editorInstance
This saves props over multiple re-renders.
Is this how getDefaultProps caching was meant to be used? On saving props over multiple re-renders am I breaking some of the core react rules with this hack? Could you suggest a better structure if so?
No, getDefaultProps is what it means to be: getting the default props in case the owner hasn't passed those to you. You could say it's a shorthand for a = this.props.bla || 'hello';.
That being said, if I'm understand your question correctly, I see three ways to solve it.
Cache that in your state instead. Props are passed by the parent and are meant to be read from, inside the child, at least in vanilla React.
Instead of putting that props passing logic in your componentDidMount, why not put it in componentDidUpdate?
ref lets you grab the instance and call its methods directly.