Reactjs component `this.state` undefined - javascript

I'm new to reactjs and tried to make a component. I set this.state in componentWillMount() and after that I call a method:
componentWillMount() {
this.setState({ value: this.props.value || "0" });
this.changeCbState = this.changeCbState.bind(this);
this.changeCbState();
}
But in my method changeCBState this.state is undefined:
changeCbState() {
console.log(this.state.value)
}
Error: Uncaught TypeError: Cannot read property 'value' of null

The problem could be that you wouldn't have initialised state in the constructor and since this.setState is asynchronous the state may not be initialsed before you are trying to access in changeCbState function.
Also the initialisation code that you have written in componentWillMount lifecycle needs to go in constructor since the componentWillMount method is supposed to be deprecated.
constructor(props) {
super(props);
this.state = {
value: this.props.value || "0"
}
this.changeCbState = this.changeCbState.bind(this);
this.changeCbState();
}

You probably didn't define state in your constructor. use the constructor to bind methods on your class instance and to define state
class Something extends React.Component {
constructor(props) {
super(props)
this.state = { value: props.value || '0' }
this.changeCbState = this.changeCbState.bind(this);
}
componentWillMount() {
this.changeCbState();
}
changeCbState() {
console.log(this.state.value)
}
}

This problem has so many different answers, but my simple elegant favorite answer is to use arrow functions when defining such function.
class Something extends React.Component {
constructor(props) {
super(props)
this.state = { value: props.value || '0' }
}
changeCbState = () => {
console.log(this.state.value)
}
componentWillMount() {
this.changeCbState();
}
}
If you want to know more about this problem which is binding in JS. read this

setState works in an asynchronous way. That means after calling setState this.state variable is not immediately changed. So you should use callback to do something after setState.
And it is better to define this.state in constructor.

Setting the state in componentWillMount is considered an anti-pattern. Take a look at this resource https://vasanthk.gitbooks.io/react-bits/anti-patterns/04.setState-in-componentWillMount.html.
The reason why state is set to null is because you haven't defined a value previously and setState is an asynchronous operation.
You have to set the initial state as follows:
class Mycomponent extends Component {
constructor(super) {
super(props);
this.state = {
value: this.props.value || "0",
};
}
}

Related

React: How do I pass props to state component?

Need help passing state as a prop to another state component. I'm very new to React and I'm not sure what I'm doing wrong. When I console.log inside the Timer component it displays undefined but when I console.log in the Main component it displays the object perfectly.
class Main extends React.Component {
constructor() {
super()
this.state = {
isLoaded: false,
itemsP:{}
}
}
componentDidMount() {
fetch("https://api.spacexdata.com/v3/launches/next")
.then(response => response.json())
.then(
(resData) =>
this.setState({
isLoaded: true,
itemsP: resData
})
)
}
render() {
console.log(this.state.itemsP) //this will console.log the object from the api
return (
<main>
<Timer nextLaunch={this.state.itemsP} />
</main>
)
}
}
//Timer component
class Timer extends React.Component{
constructor(props) {
super(props)
this.state = {
nextDate: props.nextLaunch.launch_date_utc
}
}
render() {
console.log(this.state.nextDate) //will console log UNDEFINED why is this?
return (
<div>
//display something....
</div>
)
}
}
here is the link for the API that I'm using for reference.
#tlrmacl might have answered it there. It's missing the this keyword. In theory, you might be assigning the initial value still to the state.
It is due to how react lifecycle works
On your componentDidMount(), you are calling setState after the jsx gets mounted to the DOM. this.state.itemsP is given an initial value of {} then after the mount, it will receive its new value from comopnentDidMount()
Inside your Timer component, you are assigning the first value of this.props.nextLaunch to a new state. It doesn't have the chance to update the value. Instead of doing this:
this.state = {
nextDate: props.nextLaunch.launch_date_utc
}
use props.nextLaunch.launch_date_utc directly:
console.log(props.nextLaunch.launch_date_utc)
For more information check out this tweet by Dan Abramov here
From ur parent component u pass value as nextLaunch
Dont forget to call props in ur parent component constructor
constructor(props) {
super(props);
this.state = {
isLoaded: false,
itemsP: 'myValue'
}
}
<Timer nextLaunch={this.state.itemsP} />
So in your Timer Component to print ur value you have to call ur props this way this.props.nextLaunch
class Timer extends React.Component {
render() {
return <p>My nextLaunch data are {this.props.nextLaunch}.</p>;
}
}
Hope it helps
//Timer component
class Timer extends React.Component{
constructor(props) {
super(props)
this.state = {
nextDate: this.props.nextLaunch.launch_date_utc
}
}
You need this.props instead of props in your constructor

When to use plain state over constructor(props)?

I know that their are some similar questions like this, however im still confused on the following.
When to use state like this
Class Example extends Component {
state = {
name: ''
}
}
Over constructor props
Class Example extends Component{
constructor(props) {
super(props);
this.state = {
name: ''
}
}
}
Does it have something to do with method binding ? because i can use onChange fine without binding it like this:
this.onChange = this.onChange.bind(this)
I can still call onChange like
onChange = (e) => {
}
<Component onChange = {this.onChange} />
The difference in your examples is purely syntactical, not functional. You can use both of them with the same effect.
Generally you assign a state in the constructor function when you want to compute the state based on some runtime logic (eg. based on the passed props). In that case you'll write it like that:
class Example extends Component {
constructor(props) {
this.state = {
fullName: props.firstName + ' ' + props.lastName
}
}
}
in react new version you can initialise state directly without using this
constructor(Props){
super(props)
this.state ={
}
}
both of them are correct. you can use any of them.
i will choose first one because it is less code
and for any method you can directly use them like
onChange = (e) => {
}
<Component onChange = {this.onChange} />
there is no need to bind method in new versions of react

What is the correct way to access props in the constructor?

What is the correct way to access props in the constructor ? Yes i know that in the React documentation is said that
When implementing the constructor for a React.Component subclass, you
should call super(props) before any other statement. Otherwise,
this.props will be undefined in the constructor, which can lead to bugs
To be more clear , why do wee need this.props if we can just use props inside constructor
class MyComponent extends React.Component {
constructor(props) {
super(props)
console.log(props)
// -> { something: 'something', … }
// absolutely same
console.log(this.props)
// -> { something: 'something', … }
}
}
Are there some cases when to use props over this.props ?
this.props and props are interchangeable in constructor because this.props === props, as long as props is passed to super. The use of this.props allows to detect a mistake instantly:
constructor() {
super();
this.state = { foo: this.props.foo }; // this.props is undefined
}
Consistent use of this.props makes it easier to refactor constructor body:
constructor(props) {
super(props);
this.state = { foo: this.props.foo };
}
to
state = { foo: this.props.foo };
Only this. needs to be removed.
There are also typing problems with props in TypeScript, this makes this.props preferable for typed component.
This recommendation exists to prevent you from introducing errors by calling other methods on the object from the constructor, which depend on this.props. You don't want to pass props to these explicitly.
E.g. the following would be a bug, because you call doStuff before super
class MyComponent extends React.Component {
constructor(props) {
this.doStuff()
super(props)
}
doStuff() {
console.log("something is: " + this.props.something)
}
}
The correct way is - don`t use props in your constructor - just send into a parent.
But both way is working.
So, there is one special case for reading props in a constructor and it is set default state from props.
In a constructor after call super(props) are this.props and props equals. this.props = props.
Its only about what you prefer, I prefer call always this.props.
Example:
constructor(props) {
super(props)
this.state = {
isRed: this.props.color === 'red',
}
}
Be sure, that you are calling super(props) on the first line in your constructor.

What is the reason for passing props to super() in a React constructor when props aren't accessed within it?

I've seen many code snippets such as HelloWorld, where props is passed to super().
What is the reason to do that when this.props is not accessed in the constructor?
class HelloWorld extends Component {
constructor(props) {
super(props);
this.state = { message: 'Hi' };
this.logMessage = this.logMessage.bind(this);
}
logMessage() {
console.log(this.state.message);
}
render() {
return (
<input type="button" value="Log" onClick={this.logMessage} />
);
}
}
The constructor for a React component is called before it is mounted. When implementing the constructor for a React component subclass, you should call super(props) before any other statement.
Otherwise, this.props will be undefined in the constructor, which can lead to bugs.
Read Here for more details.
If you're not going to use this.props in your constructor, you don't have to put it into super() like this:
constructor(){
super();
this.state = { randomState: "" };
this.randomProperty = null;
}
But, in some cases, props passed from the parent component can be accessed and used inside constructor for initializing state (these props are not affected by prop change). By passing props to super, you can now use this.props inside constructor.
constructor(props){
super(props);
this.state = { randomVar: props.initialValue, propDependentState: this.props.someValue };
this.someVar = props.defaultValue;
this.anotherVar = this.props.openToChangesProp;
}
Take note that those props that are directly passed to this component are the only props accessible to the constructor. props that are mapped from state using redux connect is included in the props that can't be accessed here since the component hasn't mounted yet.
You don't have to do super(props). That is done only to access props inside the constructor. You can write:
constructor(){
super()
this.state={}
}
If you do not pass super(props):
constructor(props){
super()
console.log('this.props', this.props); // => undefined
console.log('props', props); // => whatever the props is
}
Refer this stackoverflow answer

Where to set props-dependant state in a React component?

Let's say that I want to set the initial state of a component depending on a variable from the parent that is passed via props.
class MyClass extends Component {
constructor(props) {
super(props);
this.state = {};
}
I want to set the state like this:
if (this.props.foo === 'bar') {
this.setState({foo: 'bar'});
} else {
this.setState({foo: 'notBar'});
}
I put it in ComponentDidMount() and it seems to work. However, should I move it to the constructor and use the syntax this.state = {...}? Or does it belong to ComponentWillMount()? If so, is there a guarantee that the state will be rendered in time? (foo is displayed as a text field)
Since your state is assigned based on the value of proper, a good place to handle it is to assign it in the two places
ComponentWillMount/Constructor/ComponentDidMount: These are executed only once, when the component is mounted. One more thing is that if you setState in componentWillMount or componentDidMount, the it should be atleast initialised in contructor so that you don't get an undefined state error.
ComponentWillReceiveProps: This lifeCyle function is not called at the time of mounting but everytime after that the parent rerenders, so any time the prop foo changes from parent , it can be assigned to state again here
Do it like
constructor(props) {
super(props);
this.state = {
foo: ''
}
}
componentWillMount(){
if (this.props.foo === 'bar') {
this.setState({foo: 'bar'});
} else {
this.setState({foo: 'notBar'});
}
}
componentWillReceiveProps(nextProps){
if (nextProps.foo === 'bar') {
this.setState({foo: 'bar'});
} else {
this.setState({foo: 'notBar'});
}
}
Yes, it is valid to initialize state in the constructor: React Constructor Docs
So your code would be as follows:
class MyClass extends Component {
constructor(props) {
super(props);
if (props.foo === 'bar') {
this.state = {foo: 'bar'};
} else {
this.state = {foo: 'notBar'};
}
}
}
However, be aware that any change to the props in the parent will not be updated in this component, since it's only set on the constructor.
So this is only a good way to initialize state if you do not expect the parent props to change (but that is probably rare). Have a look at Lifting State Up for a guide to architect your components in a better way.

Categories

Resources