Use state, static defaultProps or a property to hold static data - reactjs

Currently, I have in my state a property holding the following value
state = {
listOfCategories = ['Bank', 'Home', 'News']
}
That piece of state is never going to change (I will use it in that component and a direct children). So I'm thinking if I should remove it from the state, which to my understanding is meant for mutable data, and put it as a property of the Class or defaultProps of that Class.
Which approach should I follow?

That piece of state is never going to change
You can even extract listOfCategories = ['Bank', 'Home', 'News'] completely outside of React tree (or put in a different file, to use it elsewhere as well).
the state, which to my understanding is meant for mutable data,
The state should be immutable because React does "shallow check" (checks if reference has been changed, not the deep comparison, which checks for changed value for nested properties as well).
a property of the Class or defaultProps of that Class.
If listCategories belongs to the current component, then it'd make sense to declare it as a property because listCategories is the component's own property, not changed by parent's props (as you said it never changes).

Well i think every solution you expose are good.
But let's come back to basic :)
You create a class with react propertys but it still a simple class.
So why not just declare this array as member of this class like this :
class test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: props.FakeData
}
this.listOfCategories = ['Bank', 'Home', 'News']
}
}
simple, easy and in my opinion the best way to do it.

Related

Mobx async example does not render result after action

You can look at the issue via codesandbox
Codesandbox: https://codesandbox.io/s/great-frog-m2s7h
Context
I am trying to fetch some data and populate some variable and render the value in React, essentially following the documentation await/async + runInAction example: https://mobx.js.org/actions.html#asynchronous-actions
However, when the data is fetched, React actually does not re-render. However, if you edit the text in there(i.e. change hi to his or whatever, then you see the correct value appear.
Problem
What exactly am I doing wrong with the data fetching? Why isn't the observable value not being re-rendered correctly when its been assigned a value after some data has been fetched?
This is actually one of the limitations of Mobx.
From the docs:
make(Auto)Observable only supports properties that are already defined. Make sure your compiler configuration is correct, or as workaround, that a value is assigned to all properties before using make(Auto)Observable. Without correct configuration, fields that are declared but not initialized (like in class X { y; }) will not be picked up correctly.
Just initialize the title this.title=undefined and it will work.
Its a simple mistake. MobX can not compare data of title to something that dosent exist. Stuff should have default value of some sort, even a null. hence in a constructor you need to define title default value like
constructor() {
this.title = [],
makeAutoObservable(this);
}
or, if you wish, even null
constructor() {
this.title = null,
makeAutoObservable(this);
}
Basiclaly, whenever you create some observable variable in a store - you need to define its default value in a constructor above makeAutoObservable.
Here, a forked project of yours with juswt this 1 line change to make it work https://codesandbox.io/s/suspicious-noether-fnhjw

When do I need to use bind() in reactJS and react native

so when I create a class I it ususally look something like this
export default class SettingsIndex extends Component {
constructor(props) {
super(props);
this.state = {
testValue: 1,
};
}
myfunction(){
this.setstate({value: 2)
}
render(){
return(
........
Question 1:
To be honest, I am not sure when I really need to have the constructor, in my understanding is that I need to declare the constructor every time a class is receiving props from a parent component, is that assumption correction?
Question 2:
see myfunction() in some classes it works without issue, however in some classes I have I get an error saying ```this.myfunction' is undefined and I then I need to bind(this) in the constructor like this
this.myfunction= this.myfunction.bind(this);
I am not sure why in some class this is accessible and not other, any idea?
You need to use the constructor only when you need to have some initialisation logic which needs to run before the first render such as initialising refs, state or binding functions. You do not require constructor just beecause your component is receiving props, React itself can do that prop forwarding for you
For your case you can define state as a class initialiser too with proper babel setup and get rid of the constructor
export default class SettingsIndex extends Component {
state = {
testValue: 1,
};
myfunction(){
this.setstate({value: 2)
}
}
Now as far as the question about binding is concerned, you first need to understand how does a function receive its context or this variable.
The this argument to a function call is received as the reference of the object on which the function is called unless the function is defined as an arrow function in which case it inherits the this variable from its surrounding scope or this is explicitly overwritten by use of call, apply or bind methods
For Example, in the lifeecycle meethods of React, the this variable already points to the class instance and calling a function using this.myFunction() will causee the myFunction to receive the context of the class as the object on which it is called is this.
On the other hand when you assign the function to an event handler, you are assigning a reference to it and when the event occurs the function is ccalled on the window reference causing the this to be undeefined and thus nneeding you to use arrow function or explicit bind to supply proper context.
Check this SO post for more details on this keyword

React TypeScript - State should never be exported?

I have a React App that gets asynchronously its info with the method getInitialInfo. The MessageView is the uppermost component, so, the Data should live in its state, even if it will not change. In a perfect world, the IMessageInfo would be passed through props.
We need to export the type IMessageInfo because there is code that depends on this interface.
OPTION 1 - (Flat solution with no private State)
import * as React from 'react';
import Message from './Message';
// IMessageInfo needs to be exported because there is code that depends on it
export interface IMessageInfo {
message: string;
icon: string;
}
export interface IMessageViewProps {
getInitialInfo(): Promise<IMessageInfo>;
}
// MessagesView is the upper most Component
class MessageView extends React.Component<IMessageViewProps, IMessageInfo> {
constructor(props) {
super(props);
this.state = {
message: '',
icon: ''
};
this.getInitialInfo();
}
private async getInitialInfo(): void{
let info = await this.props.getInitialInfo();
this.setState(info);
}
render(): JSX.Element {
// Message is reusable component that receives the info through `props`
return <Message {...this.state} />);
}
}
From the React's design perspective the State must be private to the component. I agree with that. But here, all the state info is Public. what can throw this concept way. (If the DATA is always managed in a presenter for example, why should it be private in this case?)
OPTION 2 - (Flat solution, having a private replicated interface for State)
Talking with some colleagues, they argue that we should always keep the state private. I immediately thought about creating a IMessageViewState that would be exactly the same as IMessageInfo. This way, it gets conceptually right but we would get a maintenance issue (IMessageInfo and IMessageViewState to update whenever some of its members change).
OPTION 3 - (Compose IMessageInfo into IMessageViewState. Has a private state)
So, my colleagues suggested to define IMessageViewState as:
interface IMessageViewState {
messageInfo: IMessageInfo;
}
This way we are favoring composition (they say). But I don't see any advantage to have composition here. Do you see any? For example, if any member of the IMessageInfo changes (message or icon), we would need to pass all the object messageInfo to the this.setState(...), instead of only updating the icon for example. Basically, it would be a more error-prone implementation.
OPTION 4 - (Extend IMessageInfo. Has a private state)
I also thought about having IMessageViewState extending IMessageInfo. It seems the best solution to accomplish a state that is not exported.
But my colleagues said that it's not a good solution because we are giving priority inheritance over composition.
I think that inheritance doesn't bring any throwback in here.
CONCLUSION
In my opinion, the Option 1 is the one that best fits the problem. Since all members of the State are public, I think there's no need to have a private State. The Option 1 keeps the code cleaner.
Although, if I were to choose a solution with a private State, the Option 4 would fit better.
QUESTION: What solution would be more correct?
I think here is some misunderstanding about interface and state. Interface is only type of some object. So you may have separate file which exports all required interfaces for you solution. IMessageInfo possibly can be used in several places.
State is object of some type. It can be of type IMessageInfo or some other. state is private to one component. And this is be design of React.
You may consider additional option of using Redux to make state central to whole solution. In this case IMessageInfo can be exported from part of you store responsible for MessageInfo.
Example
// store/MessageInfo.cs
export interface IMessageInfo { /*...*/ }
const initalMessageInfo: IMessageInfo = { /*...*/ }
export const actionCreators = {
requestMessageInfo () //...
}
export const reducer: Reducer<IMessageInfo> //...
In this case you'll (1) keep IMessageView sigle thru your solution, (2) make state based on IMessageInfo available to several components of your solution.
This way we are favoring composition (they say). But I don't see any advantage to have composition here. Do you see any? For example, if any member of the IMessageInfo changes (message or icon), we would need to pass all the object messageInfo to the this.setState(...),
Consider the case when you need to add more data to the MessageView internal state. This is the case the Option 3 is optimized for:
interface IMessageViewState {
messageInfo: IMessageInfo;
}
When it's separated in this way from the start, it's obvious where you can add whatever data you need to add to the private state: it's added to non-exported IMessageViewState, without affecting any users of exported IMessageInfo interface.
If you are 100% sure that IMessageInfo has everything the MessageView class will ever need, you can go with Option 1.

React use this.state or this.props?

I'm new to react an got a question about components.
I made a component like this:
class HeaderLabel extends React.Component {
constructor() {
super();
}
componentWillMount() {
this.setState({ value: String(this.props.value) });
}
render() {
return (
<div>
{this.props.value && this.props.value != "" ? <label className="control-label">{this.props.value}</label> : <label className="text-muted">({Translation.getPhrase("EMPTY")})</label>}
</div>
);
}
}
HeaderLabel.propTypes = {
value: PropTypes.string
}
export default HeaderLabel;
As you can see I'm using this.props.value to display the value. Is this the right way or is it better to use this.state.value?
Short answer: Use this.props.value.
Since you are taking the value directly from the props without mutating it somehow, there is no benefit at all in first storing it in the state and then using this.state.value.
Basically this boils down to the fundamental idea of React, which is that you should only ever have "one source of truth". By having value both in your props and in the state you have two sources of truth. As a developer, you should try to have a "master state" which passes the data down to its components.
Sometimes, however rarely, it can be a good idea to store the prop value directly to your state. For example, you might want to have a parent component which holds a string which is displayed in your app. This string can be modified in a modal which is opened when clicking the appropriate button. The "temporary under-edit" string would be in the modal-state, whereas the previously saved one still in the master component.
You might find this official blog article helpful: You Probably Don't Need Derived State
In this example, you are using the props value to display the data which you have received, then using this.props.value makes sense. Props are read-only, means the child is not the owner of that particular data and hence it cannot change anything on that data.
when to use this.state.value, let say a scenario where you get data from parent and you have to do some manipulations on that data before displaying, then, in that case, take props into a state and do the manipulations.
you can use both this.props.value and this.state.value. But first you must answer the following question. Depending on the answer you choose appropriate way of setting the value.
Which component handles the subsequent change of value received from this.props.value:
Change of value is coming from Parent component.Then you should use this.props.value.There is no need for you to assign this.props.value to this.state.value. Because the state is maintained inside parent component.
2.Change is handled by HeaderLabel component itself. Then you should set this.state.value.

Is it ok to mutate state directly before calling setState()?

I'm using a lightweight ORM to connect my react app with an external service... This package returns objects of your model and allows you to perform operations directly against them. While this is really awesome, I'm struggle to figure out how I can include these objects in state and still follow the "never modify state directly" tenant of react.
If I had a component that updated the account name, would it be acceptable to do something like this?
interface IAppState {
account: Account
}
class App extends React.Component<{}, IAppState> {
constructor(props) {
super(props);
this.state = {
account: new Account()
}
}
//set the new name and update the external service
public updateAccount = (newName: string)=>{
account.name = newName; //REDFLAG!!!
acc.update().then(()=>{
this.setState({ account: this.state.account })
})
}
//retrieve our account object from external service
public componentDidMount() {
const qParams = queryString.parse(window.location.search);
Account.get(qParams.externalId).then((acc)=>{
this.setState({account: acc})
})
}
render() {
return <NameEditor handleClick={this.updateAccount} account={a} />
}
}
I guess I could avoid mutating state by initiating a blank ORM object, copying the properties over, sending the update and then setting state, but this seems like a major pain.. Especially since these ORM objects can contain child ORM objects that I'd like to be able to modify as well.
Is the way I'm mutating state above "dangerous" or "bad form"???
Update
Did some reading and it definitely seems like this is probably bad form and might be navigated elegantly using the react/addons... However, what if the ORM call has a side effect on the object? For example, calling insert sets the objects external id field.
public updateAccount = (newName: string)=>{
//account.name = newName; //REDFLAG!!!
// You can use the below code to update name after it is updated
// on server.
// This will work because the object being passed here
// will be merged with Component state.
acc.update().then(()=>{
this.setState({account: {name : newName}})
})
}
Directly modifying state is not recommended as react will not come to know of the change and it will not cause a rerender.
All the diffing happens on Virtual DOM and react only updates the change attributes to Browser DOM. You can read more about the react diffing algorithm here.
React recommends to use immutable objects for setting state. you can either use Object.assign or immutable.js for this purpose which will make our life easier.
If you mutate your state object it will affect the the performance of your react component.
You can refer the below link for more information.
https://facebook.github.io/react/docs/optimizing-performance.html#examples

Resources