ReactJS How do i call setState nested Functions - reactjs

Lets say that i have this component:
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: false
};
}
func1 = () => {
function update() {
this.setState({ test: true }); // not working
}
};
render() {
return <div />;
}
}
As you see i have func1 which is in arrow form,and there is another function update in function update() form
So how do i call setState from inside function update as seen in example ?
EDIT:
the reason why i am trying to do something like this is i am using a game engine inside react component called phaser.So actually if i make update function as an arrow function for some reason phaser cant understand it and throws undefined error.update function is called 60 times in second
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: false
};
}
componentDidMount(){
this.func1()
}
func1 = () => {
var game = new Phaser.Game(canvas_width,canvas_height,Phaser.AUTO,'gameDiv',{ preload: preload, create: create, update: update });
function update() {
this.setState({ test: true }); // not working
}
};
render() {
return <div />;
}
}
SECOND EDIT:
THANKS GUYS WRITING update = update.bind(this) before var game solved it

You can use an arrow function again:
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
test: false
};
}
func1 = () => {
const update = () => {
this.setState({ test: true }) // not working
}
return update;
}
componentDidMount() {
this.func1()();
}
render() {
console.log( this.state);
return (
<div></div>
)
}
}
ReactDOM.render(<Test />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
When you use a regular function you lose the scope of this. When you use an arrow function you can use it without worrying about this as you do in your first function. But, instead of an arrow function that would work:
func1 = () => {
const that = this;
return function update() {
that.setState({ test: true }); // not working
}
}
Or even with bind as #Tholle suggested in his comment:
func1 = () => {
return ( function update() {
this.setState({ test: true }); // not working
}).bind(this);
}
Furthermore, you can define them separately and call the update function inside the func1.
func1 = () => {
this.update();
};
update() {
this.setState({ test: true }); // not working
}
This works too, because you are auto-binding your func1 function to this and your update function is invoked from there, keepin this scope.

you can pass this in as an argument, perhaps calling it self within the function. I.e self.setState. You could also bind or call the function passing the this as an argument. The important thing is that this still references the correct React component.
also, I'm a little confused why you're defining a function which returns a function like that. Could you just pass the function in point free form instead and not need to worry about this issue? You still need to bind the function to this..
export default class Test extends React.Component {
constructor(props) {
super(props);
this.func1 = this.func1.bind(this)
this.state = {
test: false
};
}
func1() {
this.setState({ test: true });
};
render() {
return <div callback={this.func1} />;
}
}

Related

How do I run a line of code after a function that contains setState when it is finished updating state?

How do I run anotherFunction() after myFunction() finishes in the child component without putting it inside of myFunction()? anotherFunction() will have a separate concern but is dependent on myFunction() having updated state first. Or maybe I have this completely structured wrong? Help is appreciated
class Parent extends React.Component {
constructor() {
super()
this.state = {/*...*/}
}
myFunction = () => {
//...
this.setState(/*...*/)
}
anotherFunction = () => {
//...
}
render() {
return (
<Child
myFunction={this.myFunction}
anotherFunction={this.anotherFunction}
/>
)
}
}
class Child extends React.Component {
constructor() {
super()
}
render() {
return (
<button
onClick={() => {
this.props.myFunction()
}}
>
My Button
</button>
)
}
}
setState accepts a second argument as callback which gets fired after the state is successfully changed. Try something like this:
myFunction = () => {
//...
this.setState(/*...*/, ()=>this.anotherFunction())
}
anotherFunction = () => {
//...
}
so setState does provide a callback func after it updates the state.
so in your case call another function like this and it will be fired after setState is completed.
myFunction = () => {
//...
this.setState(/*...*/, ()=>this.anotherFunction())
}
anotherFunction = () => {
//...
}
Hope this helps, feel free for doubts
setState can have a callback :)
this.setState({ name: "changed"}, ()=>{console.log(this.state.name)})

TypeError: this is undefined?

I cannot reach this.state or I cannot setState inside the componentDidMount function. Why?
import React from 'react';
class LoginApi extends React.Component {
constructor(props) {
super(props);
this.state = {
formNames: [],
};
}
componentDidMount() {
let apiKey = '###';
window.JF.initialize({ apiKey: apiKey });
window.JF.login(
function success() {
window.JF.getForms(function(response) {
for (var i in response) {
this.setState({ formNames: [...this.state.formNames, response[i]] });
}
});
},
function error() {
window.alert('Could not authorize user');
}
);
}
render() {
return (
<div className="initializeForm">
<ul>
{this.state.formNames.map(forms => (
<li key={forms}>{forms}</li>
))}
</ul>
</div>
);
}
}
export default LoginApi;
When I have tried to this code I am getting TypeError: this is undefined.
this.setState({formNames: [...this.state.formNames,response[i]]});
Because you are referencing this within another function. When you create your callback function in JF.login and again in JF.getForms with the function keyword, it creates a new this context, hence why setState is undefined.
A common way to fix this is by using an arrow function (=>), which will end up using the this from its enclosing lexical scope, which in your case is the class.
window.JF.login(
() => {
window.JF.getForms((response) => {
for (var i in response) {
this.setState({ formNames: [...this.state.formNames, response[i]] });
}
});
},
() => {
window.alert('Could not authorize user');
}
);
Because you write the success function without bind / not as an arrow function. Without it, this refers to the calling function. In this case, to the success function. Change it to an arrow function and it will work. () => {...}

Jest: How to test function that calls bind(this)

I have a Parent component that looks like this:
export class Header extends Component {
constructor(props) {
super(props)
this.state = { activeTab: TAB_NAMES.NEEDS_REVIEW }
}
filterByNeedsReview() {
const { filterByNeedsReviewFn } = this.props
this.setState({ activeTab: TAB_NAMES.NEEDS_REVIEW })
filterByNeedsReviewFn()
}
render() {
return (
...
<FilterTab
...
onClick={this.filterByNeedsReview.bind(this)}
/>
...
)
}
}
I'm trying to test that the child was loaded with the right props. Originally I had it as an anonymous function: onClick={ () => this.filterByNeedsReview() } but I couldn't test that so I tried to move on to bind(this) instead.
However, I'm having issues mocking out the bind function:
it('renders a filter tab with the right props for needs review', () => {
const bounded = jest.fn()
const boundedFilterByNeedsReview = jest.fn(() => {
return { bind: bounded }
})
Header.prototype.filterByNeedsReview = boundedFilterByNeedsReview
expect(
shallowRender()
.find(FilterTab)
.findWhere(node =>
_.isMatch(node.props(), {
... // other props
onClick: bounded, //<-------------- FAILS WHEN I ADD THIS LINE
})
)
).toHaveLength(1)
})
Bind the method in the constructor to prevent the method from re-binding every time the component renders:
constructor(props) {
super(props)
this.state = { activeTab: TAB_NAMES.NEEDS_REVIEW }
this.filterByNeedsReview = this.filterByNeedsReview.bind(this)
}
Then pass the bound method as a prop to the child:
<FilterTab
...
onClick={this.filterByNeedsReview}
/>
You don't need to use an anonymous function here.

React: fire render after promise completed

Please note, that I a fetching data from AWS DynamoDB.
...
class Test extends Component {
constructor(props) {
super(props);
this.state = {
contactList: []
}
}
componentDidMount() {
var getItemsPromise = db.scan({ TableName: "tester" }).promise();
getItemsPromise.then((data) => this.setState({ contactList: data.Items }));
}
render() {
return (
<div>{this.state.contactList[0].link.S}</div>
);
}
}
export default Test;
I am trying to render the returned value, but can't. If I set
render() {
console.log(this.state.contactList[0].link.S);
return (
<div>test</div>
);
}
it works. Why is that? Why is it not working when I set it straight inline?
this.state.contactList[0] is undefined before the promise is resolved, so this.state.contactList[0].link will give rise to an error.
You could e.g. return null from the render method until the array has been filled with your objects:
class Test extends Component {
// ...
render() {
if (this.state.contactList.length === 0) {
return null;
}
return <div>{this.state.contactList[0].link.S}</div>;
}
}

How to make this available inside render function

This is my React component:
constructor(props) {
super(props);
this.state = {
};
this.showChart = this.showChart.bind(this)
}
showChart() {
console.log('test')
}
render() {
{this.showChart} //throws error that, this is undefined
return () (
{this.showChart} //prints test
)
}
Now, if I want to call the function from render() but outside return() what should I do?
Your Component syntax is incorrect at a few places. this is available inside render.
constructor(props) {
super(props);
this.state = {
};
this.showChart = this.showChart.bind(this)
}
showChart() {
console.log('test')
}
render() {
this.showChart()
return (
<div>{this.showChart()}</div>
)
}
EDIT:
You can also work with arrow functions to bind said functions to your component. By doing this, you don't have to bind every function. It looks a lot cleaner:
constructor(props) {
super(props);
this.state = {
};
}
showChart = () => {
console.log('test')
}
render() {
this.showChart()
return (
<div>{this.showChart()}</div>
)
}
replace {this.showChart} with this.showChart()inside the render function. So your new code should be
render(){
this.showChart();
return(
{this.showChart}
);
}

Resources