I tried to call a function in set time inter val for every 5 seconds but i throws errors in
TypeError: this.intialState is not a function
componentDidMount() {
this.intialState();
setInterval(this.changeSelection,5000);
}
changeSelection(){
this.intialState();
}
TypeError: this.intialState is not a function
Updated 5-second countdown using class Clock extends Component
import React, { Component } from 'react';
class Clock extends Component {
constructor(props){
super(props);
this.state = {currentCount: 10}
}
timer() {
this.setState({
currentCount: this.state.currentCount - 1
})
if(this.state.currentCount < 1) {
clearInterval(this.intervalId);
}
}
componentDidMount() {
this.intervalId = setInterval(this.timer.bind(this), 1000);
}
componentWillUnmount(){
clearInterval(this.intervalId);
}
render() {
return(
<div>{this.state.currentCount}</div>
);
}
}
export default Clock;
this loses its context inside functions. You can bind changeSelection in the constructor
constructor() {
super();
this.changeSelection = this.changeSelection.bind(this);
setInterval(this.changeSelection, 500);
}
or make it a fat arrow function since these functions don't have their own this context and will take the parent's
changeSelection = () => {
// code here
}
An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this
componentDidMount() {
this.intialState();
setInterval(this.changeSelection,5000);
}
changeSelection = () => {
this.intialState();
}
The problem is that your function 'changeSelection' does not have access to 'this'.
There are two easy ways to solve this issue:
In your 'constructor', add this line to bind 'this' with changeSelection
this.changeSelection = this.changeSelection.bind()
An arrow function
changeSelection = () => {};
Click here to see more ways to do binding
You can read more about why we need binding why and how to bind
Related
This is what I do when I want to make this of my class functions bind to the class (component) instance. Is there any easier/more proper way to do this in React?
class App extends Component {
state = {
currentSection: 1,
message :{text:''}
};
constructor(props) {
super(props);
this.prevSection = this.prevSection.bind(this);
this.nextSection = this.nextSection.bind(this);
this.mobileChanged = this.mobileChanged.bind(this);
}
}
If I recall correctly, if you change:
function nextSection() {...}
to
const nextSection = () => {...}
After this change, you can remove this and the bind
Please let me know if your component will remain as functional like it was before. I'm not sure if it this will change the behaviour.
You could use arrow function instead of class method
With arrow function, there will be no this context so you won't have to bind it
class App extends Component {
state = {
currentSection: 1,
message: { text: '' },
};
prevSection = () => {}
nextSection = () => {}
mobileChanged = () => {}
}
Live example:
A questions about this snake game i'm developing with react.
I read on this post about setting function inside the constructor. Now for the example, I want snakeMoves function to call foodGenerator, which is in the constructor, but not in the state, so call this.state inside snakeMoves won't get me foodGenerator.
what options do I have to pass foodGenerator to snakeMoves?
class Play extends Component {
constructor(props) {
super(props)
this.state ={
gameSqueres: [],
food: null
}
this.foodGenerator = this.foodGenerator.bind(this)
}
componentDidMount() {
// create food
this.foodGenerator()
}
foodGenerator() {
console.log('food')
}
// snake move system
snakeMoves = (e) => {
const { gameSqueres } = this.state;
console.log(foodGenerator())
}
If the requirement is just to bind this and get a new function, you can use arrow functions instead. From the method snakeMoves(), simply call: this.foodGenerator()
foodGenerator = () => {
console.log('food')
}
Use this to access class methods.
snakeMoves = (e) => {
const { gameSqueres } = this.state;
console.log(this.foodGenerator())
}
You can simply just do this:
// snake move system
snakeMoves = (e) => {
this.foodGenerator();
}
So the problem I am having is that I am trying to print the textContent of my ref every 5 seconds, and this works the very first time typeWrite() is called from componentDidMount(), but when it is called recursively (using setTimeout()), I get an error saying this.intro.current is undefined, even though it was defined the first time the function ran.
I want to keep the structure relatively similar (I don't want to change it too much) because there are other things I have left out that rely on this structure.
export default class Home extends Component {
constructor(props) {
super(props);
this.intro = React.createRef();
}
componentDidMount() {
this.typeWrite();
}
typeWrite() {
console.log(this.intro.current.textContent);
setTimeout(this.typeWrite, 5000);
}
render() {
return (
<div className="intro" ref={this.intro}>Text</div>
)
}
}
You need to bind your function to your component.
constructor(props) {
super(props);
this.intro = React.createRef();
this.typeWrite = this.typeWrite.bind(this);
}
or you need to call your function with arrow function.
typeWrite() {
console.log(this.intro.current.textContent);
setTimeout(() => this.typeWrite(), 5000);
}
When we translated the previous code to ES2015 syntax, some functions got converted to a different syntax. Some of them are funcName() and some of them are funcName = () =>. What's the difference?
import React, { Component, PropTypes } from 'react';
export default class Stopwatch extends Component {
state = {
running: false,
previouseTime: 0,
elapsedTime: 0,
}
componentDidMount() {
this.interval = setInterval(this.onTick);
}
componentWillUnmount() {
clearInterval(this.interval);
}
onStart = () => {
this.setState({
running: true,
previousTime: Date.now(),
});
}
onStop = () => {
this.setState({
running: false,
});
}
onReset = () => {
this.setState({
elapsedTime: 0,
previousTime: Date.now(),
});
}
onTick = () => {
if (this.state.running) {
var now = Date.now();
this.setState({
elapsedTime: this.state.elapsedTime + (now - this.state.previousTime),
previousTime: Date.now(),
});
}
}
render() {
var seconds = Math.floor(this.state.elapsedTime / 1000);
return (
<div className="stopwatch" >
<h2>Stopwatch</h2>
<div className="stopwatch-time"> {seconds} </div>
{ this.state.running ?
<button onClick={this.onStop}>Stop</button>
:
<button onClick={this.onStart}>Start</button>
}
<button onClick={this.onReset}>Reset</button>
</div>
)
}
}
funcName() in a JavaScript class will add a function to the prototype. These functions will exist only once, attached to the prototype. Without the class syntax you would define a prototype function as follows:
Stopwatch.prototype.funcName = function() { /* ... */ };
The other functions are actually created as properties that contain anonymous functions that exist once per each instance and are created in the constructor when the class is instantiated. This is equivalent to creating them in the constructor as below:
class Stopwatch /* ... */ {
constructor() {
this.onStart = () => { /* ... */ };
}
}
The reason for doing this is that using the => syntax to create the functions causes the functions to be permanently bound to the this value of each instance. Therefore they can be passed around to other things (such as set as event handlers) and when they are called, this will always point to the correct object inside the function.
Whether this is a good idea or just plain unreadable/too tricky is perhaps a matter of taste.
Still trying to learn React. I'm trying to show an image when you hover. This is my Item component.
import React from 'react';
import Eyecon from '../../static/eye.svg';
class Item extends React.Component {
constructor(props) {
super(props);
this.displayName = 'Item';
this.state = {
hover: false
};
}
mouseOver() {
this.setState({hover: true});
}
mouseOut() {
this.setState({hover: false});
}
render() {
const { item, i } = this.props;
return (
<div className="grid-box" onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>
{this.state.hover ? (<img src={Eyecon}/>) : null}
</div>
)
}
}
export default Item;
How would I make it so only the item I hover over shows the image?
This is just a 'this' binding issue. Put a console.log inside of your mouseOver and mouseOut methods and you'll notice that your state isn't changing.
There are many ways to bind the 'this' context in your class methods. I'll show you three ways to do it in this example (DO NOT do all three methods, just choose one).
import React from 'react';
import Eyecon from '../../static/eye.svg';
class Item extends React.Component {
constructor(props) {
super(props);
this.displayName = 'Item';
// 1. bind your functions in the constructor.
this.mouseOver = this.mouseOver.bind(this);
this.mouseOut = this.mouseOut.bind(this);
this.state = {
hover: false
};
}
// 2. bind it with fat arrows.
mouseOver = () => {
this.setState({hover: true});
}
mouseOut() {
this.setState({hover: false});
}
render() {
const { item, i } = this.props;
// 3. bind them in the render method (not recommended for performance reasons)
return (
<div className="grid-box" onMouseOver={this.mouseOver.bind(this)} onMouseOut={this.mouseOut.bind(this)}>
{this.state.hover ? (<img src={Eyecon}/>) : null}
</div>
)
}
}
export default Item;
Here's an explanation of different ways to bind your 'this' context in react using ES6 classes:
http://egorsmirnov.me/2015/08/16/react-and-es6-part3.html
Maybe it's because you have to bind mouseOver and mouseOut calls in order to use this.setState inside them.
Replace:
<div className="grid-box" onMouseOver={this.mouseOver} onMouseOut={this.mouseOut}>
with:
<div className="grid-box" onMouseOver={this.mouseOver.bind(this)} onMouseOut={this.mouseOut.bind(this)}>
The other solutions suggested are perfectly valid, however you can solve this easily by just converting your functions to ES6 arrow functions.
An arrow function expression has a shorter syntax compared to function expressions and lexically binds the this value (does not bind its own this, arguments, super, or new.target). Arrow functions are always anonymous.
Like so:
mouseOver = () => {
this.setState({hover: true});
}
mouseOut = () => {
this.setState({hover: false});
}
Simple.