React How to destruct deep props in constructor? - reactjs

I have the following constructor in my class component:
constructor(props) {
super(props);
this.state = {
dirty: this.props.form.dirty // error happens here!
};
}
eslint returns an error for destructing the props. How is it possible for deeper props like this?

It is not a error per se. But you could use something like this to avoid the warning.
const { dirty } = props.form;
this.state = { dirty };
OR
const { form: { dirty } } = props;
this.state = { dirty };

First of all, don't use this.props inside constructor as you are getting props as an argument.
Secondly for destructuring, you could do something like this:
const {form: {dirty = 'any initial value in case of undefined'}} = props;
this.setState = {
dirty
}

Related

Where to set state when I need that state in render?

I am getting this error below:
react_devtools_backend.js:2430 Warning: Cannot update during an existing state transition (such as within `render`). Render methods should be a pure function of props and state.
From the error, I know I am getting it because I am setting state in the render.
But I am not sure where to set the state because I need that state element, developerTitle further down inside the render method.
Where can I put it if not in render?
Thanks!
Here is my code:
export default class Game extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
developerTitle: ''
}
}
render() {
const { indieDeveloperId } = this.props;
this.setState({ developerTitle: this.getDeveloperTitle(game.indieDeveloperId) });
<div>
<h3>{this.state.developerTitle}</h3>
...
...
</div>
}
//by-indie-developer/{indieDeveloperId
async getDeveloperTitle(indieDeveloperId) {
const r = await axios.get(`/api/developer/by-indie-developer/${indieDeveloperId}`);
const developerTitle = r.data;
this.setState({
...this.state, ...{
developerTitle: developerTitle
}
});
}
}
You can't set a state in render(). But you can set a state when the component is loaded using the componentDidMount() function.
Add a function with that name like this to your component:
componentDidMount() {
this.setState({ developerTitle: this.getDeveloperTitle(game.indieDeveloperId) });
}
You dont have to call the function. The state will automatically be set.

How to initialize the react functional component state from props

I'm using React hooks for app state, I wondered about how to initialize the functional component state using props? The useState hook doc says something definitive like,
const [count, setCount] = useState(0);
I want to initialize that 0 value by the value of props being passed to the component. The Older as,
import React from 'react';
export default class Sym extends React.Component{
constructor(props){
super(props);
this.state = {
sym : [0,3,2,8,5,4,1,6],
active: this.props.activeSym
}
this.setActive = this.setActive.bind(this);
}
setActive(itemIndex){
this.setState({
active: itemIndex
});
}
render(){
return (
<div><h1>{ this.state.sym[this.state.active]}</h1></div>
);
}
}
works fine. Where the parent Component passes activeSym prop and Sym component initializes the state with it using this.props.activeSym in constructor. Is there any workaround to achieve same in function component?
First you can define it from props (if the prop exist):
const [count, setCount] = useState(activeSym);
And then you can update this value, when prop doesn't have a value immediately (when component rendered):
useEffect(() => {
if (activeSym) {
setCount(activeSym);
}
}, [activeSym])
Yes, this can be possible with functional component too! You just need to add useEffect to listen to prop change for initializing state with prop value
export const newComponent = (props) => {
const { path, value, info, update } = props;
const [val, setVal] = useState(value);
useEffect(() => {
setVal(value);
}, [value]);
return <div>{val}</div>;
};
Attching sandbox link
https://codesandbox.io/s/confident-agnesi-ohkq7?file=/src/MakeComponent.js
Yes you can first define state using props:
const [name, setName] = useState(props.obj?.name);
And then you can if the state is still undefined means props doesn't have a value, then:
useEffect(() => {
if (JSON.stringify(props.obj) !== "{}") {
setName(props.obj?.name);
}
}, [props.obj])
Just as follows :
const MyFunctionalComponent = ({myProp}) => {
const [count, setCount] = useState(myProp)
return (
/* ... */
)
}
There are two ways you can change the state:
one is using this.state and
another one is this.setState.
We use the first method to initialize the state in the constructor, and the second method is used for the rest of the time.
Initialize State in the Constructor
One way is to initialize the state is in the constructor. As we discussed earlier constructor is the first method to be called when React instantiates the class. This is the perfect place to initialize the state for the component because the constructor is called before the React renders the component in the UI.
class WithConstructor {
constructor() {
this.state = {
name: "StackOverflow"
}
}
}
Initialize State Without Constructor
Another way of initializing state in React is to use the Class property. Once the class is instantiated in the memory all the properties of the class are created so that we can read these properties in the render function.
class WithoutConstructor {
state = {
name: "StackOverflow"
}
}

React add unmounted component to the array

Im trying to create multiple components for future rendering adding tham to the array like this:
widgets.push(<TextWidget fieldData={fieldData} correctionFactor={correctionFactor} />);
but in my component I'm getting
TypeError: Cannot set property 'FieldData' of undefined
class TextWidget extends Component {
FieldData = null;
CorrectionFactor = null;
state = {
FieldData: null,
CorrectionFactor: null
}
constructor(props) {
this.FieldData = props.fieldData;
this.CorrectionFactor = props.correctionFactor || 1;
}
componentDidMount() {
this.state.FieldData = this.FieldData;
this.state.CorrectionFactor = this.CorrectionFactor;
}
....
if i do smth like this.state.FieldData = props.FieldData; in a constructor then react is complaining about being unable to set state of unmounted component.
I think that you forgot call super() inside your constructor as a first line
super(props);
According to the React docs:
You should call super(props) before any other statement. Otherwise, this.props will be undefined in the constructor, which can lead to bugs.
You're committing two mistakes.
First: You should call the super(props) before manipulating the props, then use the this.props.FieldData, and you could do it even in the constructor(), when defining the state, like:
constructor(props) {
super(props);
this.state = {
FieldData: this.props.FieldData,
CorrectionFactor: this.props.CorrectionFactor || 1
};
}
Second: You shouldn't set state like you did:
this.state.FieldData = this.FieldData;
You should use the this.setState()(read the docs), like below:
this.setState({
FieldData: this.props.FieldData,
CorrectionFactor: this.props.CorrectionFactor
});

Is Initializing state with props object causes mutation?

In my React application, one of the components needs state initialization from props.
Class ComponentA extends React.Component{
constructor(props){
this.state = {
objectA: props.objectA
}
}
someOnclickFunction(e){
let updatedObjA = this.state.objectA;
updatedObjA.value = e.target.value;
this.setState({
objectA: updatedObjA
})
}
}
In the above code snippet, props.objectA reference is copied to state. So, Am I mutating the props indirectly by updating the state?
Or setState() function will clone the object and keep new reference for the objectA?
class ComponentA extends React.Component {
constructor(props) {
super(props);
// state is null at this point, so you can't do the below.
// this.state.objectA = props.objectA
// instead, initialize the state like this:
this.state = {
objectA: props.objectA,
};
}
someOnclickFunction(e) {
// you can't set "objectA.value" like the following
// this.setState({
// objectA.value: e.target.value
// });
// you need to create a new object with your property changed, like this:
this.setState({
objectA: Object.assign({}, this.state.objectA, { value: e.target.value }),
})
}
}
This is a mistake that many beginners at react make. You can't simply update sub-properties of an object without consequences.. The following would also be wrong:
someOnclickFunction(e) {
var tmp = this.state.objectA;
// WRONG: don't do this either, you're modifying the state by doing this.
tmp.value = e.target.value;
this.setState({
objectA: tmp,
});
}
To elaborate on the correct way to do this using Object.assign.. this function takes all the parameters and merges them into the first element. So by providing a new object as the first parameter, you've created a copy of your first object with your new property.
Object.assign({}) // = {}
Object.assign({}, objectA) // = copy of objectA
Object.assign({}, objectA, { value: "newValue" }) // = copy of objectA with 'value' = 'newValue'.
Note: Object.assign() is a shallow clone, not a deep clone.

Uncaught TypeError: Cannot read property 'state' of undefined - React

I can not figure out if I am missing something small here?
Just trying to get a grasp on how state works with React.
Just creating a small check box that changes text on check/uncheck.
import React from 'react';
export default class Basic extends React.Component {
constructor(props) {
super(props);
this.state = {
checked: true
};
}
handleCheck() {
this.setState = ({
checked: !this.state.checked
});
}
render() {
var msg;
if (this.state.checked) {
msg = 'checked'
} else {
msg = 'unchecked'
}
return (
<div>
<input type="checkbox" onChange={this.handleCheck} defaultChecked={this.state.checked} />
<h3>Checkbox is {msg}</h3>
</div>
);
}
}
Changes:
1. You forgot to bind the onChange method, either use this:
onChange={this.handleCheck.bind(this)}
or define the binding in the constructor:
this.handleCheck = this.handleCheck.bind(this)
2. You used setState in a wrong way, setState is a method you need to call it.
Instead of: this.setState = ({})
it should be: this.setState({})
Binding your handleCheck function in the constructor:
constructor(props) {
super(props);
this.state = {
checked: true
};
this.handleCheck = this.handleCheck.bind(this);
}

Resources