React: How to read state from within handler function? - reactjs

I'm new to React working on an existing React component (that appears to be built in an older style - no hooks).
I want to read and set state within a handler function. I have the following code:
export default class MyComponent extends React.Component {
static defaultProps = {
data: {}
};
constructor(props) {
super(props);
// Other states
this.state.myState = false;
};
handleMyChange() {
if (!this.state.myState) {
console.log("hello world");
}
}
However I get the error Cannot read properties of undefined.
I've tried various like state.myState but am not really sure what I should be doing.
Can anyone point me in the right direction?

In order to have this context in your function, you will need to bind it in the constructor first
Here is a small example is taken from the official doc:
import React from "react";
export default class SayHello extends React.Component {
constructor(props) {
super(props);
this.state = { message: "Hello!" };
// This line is important!
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert(this.state.message);
}
render() {
// Because `this.handleClick` is bound, we can use it as an event handler.
return <button onClick={this.handleClick}>Say hello</button>;
}
}

Related

Class variables in REACT

Does class variables in a class need to be a part of the stateObject? I tried below with no luck. Here there is samples with simple variables so I am kind of surprice below does not work (alert says undefined)?
https://www.w3schools.com/react/react_es6.asp
https://codesandbox.io/s/jovial-glade-lfv4f?fontsize=14&hidenavigation=1&theme=dark
import React, { Component } from "react";
class Test extends Component {
constructor(props) {
super(props);
this.variable = "works";
}
clicked() {
alert(this.variable);
}
render() {
return <div onClick={this.clicked}>CLICK ME</div>;
}
}
export default Test;
You need to use bind() call to make it work.
constructor(props) {
super(props);
this.variable = "works";
this.clicked = this.clicked.bind(this);
}
for more information on this checkout Handling events in React
Why you have to bind here? so this is because you are using ES6 syntax for your components, and in ES6 class methods are not bound to classes by default, and to be able to use this keyword inside your methods and make it refer to the class instance you have bind your method to the class like in this answer.
import React, { Component } from "react";
class Test extends Component {
constructor(props) {
super(props);
this.variable = "works";
}
clicked = () => {
alert(this.variable);
}
render() {
return <div onClick={this.clicked}>CLICK ME</div>;
}
}
export default Test;
You can choose not to bind but you need to be adding fat-arrow function syntax in order to make it work.

Cannot read property 'checked' of undefined, from React.Component static funtion

I have a React.Component and i want to call this static function from the many different React.Component.
class Categories extends React.Component {
constructor(props) {
super(props);
this.getCheckedCategories = this.getCheckedCategories.bind(this);
this.state = {
checked: [],
unchecked: []
};
}
static getCheckedCategories() {
return this.state.checked;
}
}
So I tried to connect the function.
import Categories from './product/checkboxes';
class FullWidthGrid extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
const { classes } = this.props;
const checkedCategories = Categories.getCheckedCategories();
}
}
static functions can't access this, i.e. static method calls are made directly on the class and are not callable on instances of the class. You can read more on that here.
So in your case you could do:
class Categories extends Component {
state = {
checked: [],
unchecked: []
};
static getCheckedCategories = (klass) => {
return klass.state.checked
}
render() {
return (
<div>{Categories.getCheckedCategories(this)}</div>
);
}
}
Working example here.
That's the purpose of static function. It cannot access the instance (this).
You can have multiple instances of class but only one static function/property.
As a workaround (depend on what you want to do), you can use static property to store your state:
class Categories extends React.Component {
constructor(props) {
super(props);
Categories.state = {
checked: [],
unchecked: []
};
}
static getCheckedCategories() {
return Categories.state.checked;
}
}
However it won't work with setState since it is an instance method.
Imagine situation when you have muptiple Categories components and each one has different checked/unchecked categories. What would then Categories.getCheckedCategories() function returns?
If you want to have shared state (checked categories), I would recommend you to pull out the state out of the component. For example store it in parent component and pass it as props to child components. Or use state library like redux. You could also use react's context to manage shared state.

How to get updated data into constructor in React

// parent class
export default class HomeScreen extends React.Component {
constructor(props){
super(props);
this.state = {
password: '',
username:'',
session: 'mani',
};
}
authentication(){
const self = this;
axios.post('/api/users/login/', {
password: this.state.password,
username: this.state.username
})
.then(function (response) {
console.log(response);
var sessionid=response.headers["set-cookie"][0].split('Secure,').pop().split(';').shift();
self.setState({session: sessionid });
})
.catch(function (error) {
console.log("Invalid username/password");
});
}
render(){
return(<Session sessid={this.state.session}/>);
}
}
export default class Session extends Component {
constructor(props){
super(props);
this.sessionVariable = this.props.sessid;
}
render(){
console.log(this.props.sessid); // here i am getting updated value
console.log("constructor "+this.sessionVariable); // here i can't able to get updated value
return (<View></View>);
}
}
//child class
import React, { Component } from 'react'
import { View, Text } from 'react-native'
export default class Session extends Component {
constructor(props){
super(props);
this.state = {
sessid: this.props.sessid
}
}
componentWillReceiveProps(nextProps){
const { sessid } = nextProps;
if (sessid !== this.state.sessid) {
this.setState({sessid});
}
}
render(){
console.log(this.props.sessid);
console.log("dummy"+this.state.sessid);
return (<View></View>);
}
}
How to get updated data into constructor in React
Can you please give me the quick solution
I need to update the data in constructor . Then only I am able to call the global variable throughout the all components
How to get updated data into constructor in React
Can you please give me the quick solution
I need to update the data in constructor . Then only I am able to call the global variable throughout the all components
Add your props value inside the state and update it using componentWillReceiveProps ' lifecycle.
constructor(props) {
super(props);
this.state = {
sessid: this.props.sessid;
};
}
componentWillReceiveProps(nextProps){
const { sessid } = nextProps;
if(sessid !== this.state.sessid) {
this.setState({sessid});
}
}
You can use states to check that current condition, let me explain it with an example,
This is the constructor with initial state for the data toggle
constructor(props){
super(props);
this.state = {
toggle: true;
}
}
Update the existing state, do this
this.setState({ toggle: false });
Make sure you are using the above code inside an arrow function or else bind the .this
If you want more info comment that below...
The only reason that it doesn't show the updated value is because constructor is called only on the initial mount of the component and hence whatever class variable is set in constructor based on props, it won't be updated if the props change.
Second: setting a state or a class variable which is directly derivable from props is an anti pattern and you should just use props directly in render
export default class Session extends Component {
render(){
console.log(this.props.sessid);
return (
<View>
</View>
)
}
}
Still if you want to update the class variable based on, you can make use of componentWillReceiveProps function like
componentWillReceiveProps(nextProps) {
if(nextProps.sessid !== this.props.sessid) {
this.sessionVariable = nextProps.sessid;
this.forceUpdate(); // called to cause a re-render
}
}
or
export default class Session extends Component {
constructor(props) {
super(props);
this.state = {
sessionVariable: props.sessid
}
}
componentWillReceiveProps(nextProps) {
if(nextProps.sessid !== this.props.sessid) {
this.setState({ sessionVariable: nextProps.sessid});
}
}
render(){
console.log(this.state.sessionVariable);
return (
<View>
</View>
)
}
}
In your constructor define a state:
constructor(props) {
super(props);
this.state = {
sessionVariable: props.sessid;
};
}
Now, in your render():
console.log(props.sessid);
console.log("constructor "+ this.state.sessionVariable);
The constructor for a React component is called only before it is mounted. If you define some variable in constructor, it will store its value not reference and will not be re render again.
To change any value defined in constructor, you need to change it in updating phase of react (ComponentWillReceiveProps) and then call the
this.forceUpdate(); // to render the component
eg.
componentWillReceiveProps(nextProps) {
if(this.props.sessid !== nextProps.sessid) {
this.sessionVariable= nextProps.sessid;
this.forceUpdate();
}
}
Or you can directly use props in render function.

How to declare ReactJS default props when using Redux?

What is the right way to declare default props in react so that when I call map on a prop that is asynchronously assigned using redux I do not get an undefined error? Right now, with the following syntax I get an error when trying to assign trans_filter because data is undefined in the initial call to render.
class ContainerComponent extends React.Component {
static defaultProps = {
searchProps: {
data: []
}
};
constructor(props) {
super(props);
}
render(){
let trans_filter = JSON.parse(JSON.stringify(this.props.searchProps.data));
}
}
const mapStateToProps = (state) => ({
searchProps: state.searchProps
});
export default connect(mapStateToProps, {getTransactionsAll})(ContainerComponent);
Here's how you can declare default props when using the ES6 class syntax for creating ReactJS components:
class ContainerComponent extends React.Component {
constructor(props) {
super(props);
}
render(){
let trans_filter = JSON.parse(JSON.stringify(this.props.searchProps.data));
}
}
ContainerComponent.defaultProps = {
searchProps: {
data: []
}
};
export default ContainerComponent;
Additionally, there is another syntax for declaring defaultProps. This is a shortcut, but it will work only if your build has ES7 property initializers turned on. I assume that's why it doesn't work for you, because I see no issues with your syntax:
class ContainerComponent extends React.Component {
static defaultProps = {
searchProps: {
data: []
}
};
constructor(props) {
super(props);
}
render() {
let trans_filter = JSON.parse(JSON.stringify(this.props.searchProps.data));
}
}
export default ContainerComponent;
Edit: after you shared your mapStateToProps, yes, it has something to do with Redux!
The issue is caused by your reducer. You must declare initial state shape and moreover, you must specify the initial state in each reducer. Redux will call our reducer with an undefined state for the first time. This is our chance to return the initial state of our app.
Set initial state:
const searchPropsInitialState = {
data: []
};
Then, in your reducer when you manipulate searchProps do:
function yourReducer(state = searchPropsInitialState, action) {
// ... switch or whatever
return state;
}
For more details, see handling actions in the Redux docs.

Why is the getState() function defined outside of the React component in most flux examples

I'm mostly just curious what the significance of this pattern is. In almost every example I've looked at for using the flux architecture the getAppState() function is defined right above the react class definition. Why? Why is it not a function of the component?
So why is this:
import React from 'react';
getAppState = () => {
return {
something: SomeStore.getState()
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = getAppState();
}
}
Better than this:
import React from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = this.getAppState();
}
getAppState() {
return {
something: SomeStore.getState()
}
}
}
And what if I'm wanting to pass arguments from this.props into the getAppState() function?

Resources