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.
Related
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.
I currently use the useEffect hook to run some function or update a variable as an effect of another value/variable being changed
example:
useEffect(() => {
setValues(types[formStep]]);
}, [formStep]);
I am using the above code to update a variable after another variable has changed, however i keep getting the warning that
React Hook useEffect has a missing dependency 'types
and obviosuly when i include 'types' as a dependency, the application falls into a loop and i get the following error
Maximum update depth exceeded.
What is the best way to achieve the variable update but avoid the error? not just for this example for for all cases where you need to update a variable depending on another variable changing before it.
Some solutions found here: https://www.benmvp.com/blog/object-array-dependencies-react-useEffect-hook/.
Another option could be to stringify the dependency so that it is not treated as a different object everytime.
useEffect(() => {}, [JSON.stringify(data)])
What is the best way to achieve the variable update but avoid the error?
It depends on a lot of factors: sometimes using a ref (if you don't want to trigger an update), sometimes you are just deriving state and there is not need for use-effect (I think that this could be your case), other times you need to trigger an update only when certain value(s) has changed... Sometimes the next value depends on the previous one so you should use the function overload of setState and avoid passing the previous value as a dependency... There is not a generic answer to this problem.
It's difficult to know what's happening in your case without more context. However, I think that I have an idea of what could be happening... This is just a shot in the dark.
Is types an Object that you are defining inside the function of the component? Can you move that definition outside of the function of the component? Because if you can do that, then there is no need to pass it as a dependency.
Also, do you really need to use useState and useEffect for setting values? Do you really need to trigger another update? can't you just do this?
const values = types[formStep];
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 currently working on an Angular component where I would like to have a dynamic store name, for my ngrx/store(feature module). As a result, I have added an #Input() storeName: string; value to my component. I want to be able to specify the storeName on the html DOM and pass it to the store. That, however, is my precise issue. I am not sure as how to pass an #Input() value from my component to my module.
The idea is:
StoreModule.forFeature('myStoreName', myReducer, {initialState: myInputInitialState}).
so that instead of myStoreName, it can be the #Input value created on the component. Any suggestions are more than welcome. Thank you.
All things considered, I realized what I was doing was an anti-pattern. Even if I would have the option to instantiate a module, with an input value passed through a component(which for reasons of AOT I cannot), those values would ultimately have to be passed elsewhere.
Instead, I did indeed give this component a state feature name that is static. However, this state get's passed elsewhere, when a particular event handler is called. Staying true to what this input component is supposed to be, a temporary state, until user is able to submit, or any other event for that matter. I believe this to be similar for all other situations with dynamic components.