How to use setInterval with React? - javascript

I want the following app to print DAnce every second on the screen.
import React from 'react';
import ReactDOM from 'react-dom';
export class Sample extends React.Component {
sample(text, i) {
return <h1> DAnce</h1>;
}
render(){
return (
<div className="text-intro" id="site-type">
{setInterval(()=>this.sample('igod',1),1000)}
</div>
);
}
}
ReactDOM.render(
<Sample />,
document.getElementById('root')
);
Instead I get 5 printed on the screen.
How do I obtain the desired effect?

You could store a count in your state, and use an interval to increment this count every second and create count many Dance in the render method.
Example
class Sample extends React.Component {
state = { count: 0 };
componentDidMount() {
this.interval = setInterval(() => {
this.setState(previousState => {
return { count: previousState.count + 1 };
});
}, 1000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
render() {
return (
<div className="text-intro" id="site-type">
{Array.from({ length: this.state.count }, () => <div>Dance</div>)}
</div>
);
}
}
ReactDOM.render(<Sample />, 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>

You have to think has the text as something that is changing in your app. That is ideal for state.
I don't know what your functions sample does. But let's say you have it declared.
const sample = (text, i) => { ... };
Then you can do it like this:
class Sample extends Component {
state = {
text: sample('igod', 1),
};
componentDidMount() {
setTimeout(() => {
this.setState({
text: this.sample('igod',1)
});
}, 1000);
}
render() {
return (
<div className="text-intro" id="site-type">
{this.state.text}
</div>
);
}
}
Basically what happens is, when your component mounts you will start a timeout where every 1 second it will update the state thus updating your UI.

Try this,
import React from 'react';
import ReactDOM from 'react-dom';
export class Sample extends React.Component {
sample(text, i) {
return <h1> DAnce</h1>;
}
render(){
return(
<div className="text-intro" id="site-type">
{setTimeout(()=>{this.sample('igod',1)}, 1000)}
</div>
);
}
}
ReactDOM.render(
<Sample />,
document.getElementById('root')
);

You have used setTimeout which will be called only number of times while component renders.
You need to use setInterval to work each second.
Replace with this. Hopw this will help you.
{setInterval(()=>this.sample('igod',1),1000)}

What if you use the react lifecycle:
export class Sample extends React.Component {
sample(text, i) {
this.setState({ text });
}
render(){
return(
<div className="text-intro" id="site-type">
<h1>{this.state.text}</h1>
{setTimeout(()=>this.sample('igod',1),1000)}
</div>
);
}

Related

why the state in react component isn't declared with var/let/const variable prefixes

why state in react component isn't declared with var/let/const variable prefixes?
import React, { Component } from 'react'
class Counter extends Component {
state = {
}
render() {
return (
<>
<h1>Hello World</h1>
<button>Increment</button>
</>
)
}
}
export default Counter
They're called class fields and they were introduced as part of the ES6 revisions.
class Example extends React.Component {
state = { count: 0 };
handleClick = () => {
let { count } = this.state;
count++;
this.setState({ count });
}
render() {
const { count } = this.state;
return (
<div>
<p>You clicked {count} times</p>
<button onClick={this.handleClick}>
Click me
</button>
</div>
);
}
};
// Render it
ReactDOM.render(
<Example />,
document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
That's just part of JavaScript class syntax. You are defining a field in the class Counter, which should be initialized to a new {} every new class instance.
You'd access it with this.state within the class, not as a regular variable.

How can I update the state from parent component to child component when its passed as a prop?

So I have the parent component that sets the counter for score and I'm passing it to the child component. I have a function in the parent component called resetBoard() that I need to use to reset that counter back to 0. Currently this code does not update the state for score when the button is pressed. The full results displays the current still instead of resetting to 0.
import React from 'react';
import ReactDOM from 'react-dom';
import Player from './Player';
class App extends React.Component {
state = {
players: 2,
score: 0
}
resetBoard = () => {
this.setState( { score: 0} )
}
render() {
return(
<div>
<Player score={this.state.score} name={(this.state.players <= 2 ? "Team One" : "Player One")}/>
<button onClick={this.resetBoard}>Reset Board</button>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
import React from 'react';
export default class Player extends React.Component {
state = {
score: this.props.score
}
updateScoreFive = () => {
return this.setState({score: this.state.score + 5})
}
componentDidUpdate() {
if (this.state.score >= 150) {
console.log('winner')
}
}
render(props) {
return (
<div>
<h1>{this.props.name}</h1>
<p>{this.state.score}</p>
<button onClick={this.updateScoreFive}>5</button>
</div>
)
}
}
Parent component
resetBoard = () => {
this.setState({counter: 0});
}
Pass this function to child component.
<ChildComponent onClick={this.resetBoard }/>
Now in Child component use it on button.
<button onClick={props.onClick} />
or
<button onClick={this.props.onClick} />
The score state should all be stored/updated in one place, instead of having both parent and child have their own state. If you store it all in App's state, and move updateScoreFive into App as well, you can pass the score and a reference to the function down into Player, which can be converted to a stateless functional component:
import React from 'react';
export default function Player = (props) => {
if (props.score >= 150) {
console.log('winner');
}
return (
<div>
<h1>{props.name}</h1>
<p>{props.score}</p>
<button onClick={props.updateScoreFive}>5</button>
</div>
)
}
And in App:
<Player updateScoreFive={this.updateScoreFive} ... />
This is a good article on how to think about where state should be stored: https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0

ReactJS How to pass child component values to parent component

I have below codes
chat.js
import React from 'react';
import '../styles/Chat.css';
import Web from '../services/Web';
class Chat extends React.Component {
constructor(props) {
super(props);
this.state = {
msg:''
};
this.sendMessage = this.sendMessage.bind(this);
}
sendMessage () {
this.props.updatecommentText(this.refs.newText.value, this.props.index);
this.setState({ msg: '' });
}
render() {
return (
<div className="Chat-container">
<div className="Chat-row">
<div className="Chat-column">
<div className="Chat-card">
<div className="Chat-body">
<div className="Chat-title">React Based Chatbot</div>
<div className="Chat-messages">
{ this.props.children }
</div>
</div>
<div className="Chat-footer">
<textarea className="Chat-input" ref="newText"></textarea>
<button className="Chat-submit" onClick={this.sendMessage} defaultValue={ this.props.children }>Send</button>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default Chat;
Web.js
import React, { Component } from 'react';
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import Chat from '../components/Chat';
class Web extends React.Component {
constructor(props){
super(props);
this.state = {
messages:["Hi, How can I help you ?"
]
};
this.sendtobot = this.sendtobot.bind(this);
}
sendtobot(newText, i){
var arr = this.state.messages
arr.push(newText)
this.setState({messages: arr})
}
eachMessage(message, i){
return (<Chat key={i} index={i} updatecommentText={ this.sendtobot.bind(this) }>{ message }</Chat>);
}
render(){
return(
<div>
{this.state.messages.map(this.eachMessage.bind(this))}
</div>
)
}
}
export default Web;
I wanted to take the input from the Chat.js and send it to Web.js and push that value to array messages and then again render that array in the this.props.children in Chat.js
But, while running the code, I am getting an error this.props.updatecommentText is not a function.
Can someone please help me with this.
You have bind this.sendtobot twice. It should be only in the constructor.
like this
eachMessage(message, i){
return (
<Chat key={i} index={i} updatecommentText={this.sendtobot}>
{ message }
</Chat>
);
}
Your code seems to work.
Here is a sandbox with your code.
I'm not sure it works as you would expect, but it works without errors.
By changing this 3 functions in Web component, it starting to look like a chat with only one textarea
sendtobot(newText, i) {
this.setState({ messages: [...this.state.messages, newText] })
}
eachMessage(message, i) {
return (<p>{message}</p>);
}
render() {
return (
<div>
{this.state.messages.map(this.eachMessage.bind(this))}
<Chat updatecommentText={this.sendtobot}/>
</div>
)
}
You can pass child's component state to parent component using redux also as global state.

React Dynamically add n divs to the page on button click

I am new to react, I want my webpage to initially have 20 rectangle and then when I click a button the virtual DOM should reload and add 20 more boxes.
I have thought about setting state to 20 initially and then incrementing it by 20 everytime the button is clicked but I am not sure what to do next, do I need to run a loop till the value of state and add the divs or is there some other better way of dynamically adding elements.
Here is the code so far:-
index.js
import React from 'react';
import { render } from "react-dom";
import { Sample } from "./components/Sample";
class App extends React.Component {
render() {
return (
<div className="wrapper">
</div>
);
}
}
render(<App />, window.document.getElementById("app"));
Sample Component
Sample.js
import React from "react";
import { index } from "./../index";
export class Sample extends React.Component {
constructor() {
super();
this.state = {
count: 20
}
}
incrementCount() {
this.setState({
count: this.state.count += 20
});
}
render() {
return (
<div>
// Dynamically add divs to index.js
<button onClick="incrementCount">Generate new boxes</button>
</div>
);
}
}
In your incrementCount() method, you can't modify state directly, you can change it to:
this.setState({
count: this.state.count + 20
});
Then, you can dynamically rendering different number of divs by creating a for loop:
getrDivList () {
var divList = null;
for (var i = 0; i < this.state.count; i++) {
divList.push(<div />);
}
return divList;
}
render() {
return (
<div>
// Dynamically add divs to index.js
{ this.getrDivList() }
<button onClick="incrementCount">Generate new boxes</button>
</div>
);
}

setState in ReactJS

I'm new to ReactJS and I can't seem to find out why the result of the following setState is not as I expect it to be (i.e. to increment the value every second by 1)
import React from 'react';
import ReactDOM from 'react-dom';
class Layout extends React.Component {
constructor() {
super();
this.state = {
name: "Behnam",
i: 0
}
}
render() {
setInterval(() => {
this.setState({ name : "Behnam" + this.state.i });
this.setState({ i: this.state.i + 1 });
}, 1000);
return (
<div className="container">
{this.state.name}
</div>
);
}
}
ReactDOM.render(<Layout />, document.getElementById('app'));
Instead the output string rapidly increases (I guess as fast as react is trying to keep its' virtual DOM updated). So I was wondering what is the right way to do this?
Every time you change the state, you rerender the component.
Because you initiated the setInterval in the render method, you get another interval, which changes the state, and rerenders, and so on.
Move the setInterval to componentDidMount, which is invoked only once, when the component mounts:
import React from 'react';
import ReactDOM from 'react-dom';
class Layout extends React.Component {
constructor() {
super();
this.state = {
name: "Behnam",
i: 0
}
}
componentDidMount() { set the interval after the component mounted, and save the reference
this.interval = setInterval(() => {
this.setState({
name: `Behnam${this.state.i}`,
i: this.state.i + 1
});
}, 1000);
}
componentWillUnmount() {
this.interval && clearInterval(this.interval); // clear the interval when the component unmounts
}
render() {
return (
<div className="container">
{this.state.name}
</div>
);
}
}
ReactDOM.render(<Layout />, document.getElementById('app'));
Currently, it is creating an interval every time the component is rendered, so there are multiple timers incrementing the value. You probably want to do it in componentDidMount() instead of render(). See docs.
import React from 'react';
import ReactDOM from 'react-dom';
class Layout extends React.Component {
constructor() {
super();
this.state = {
name: "Behnam",
i: 0
}
}
componentDidMount() {
setInterval(() => {
this.setState({ name : "Behnam" + this.state.i });
this.setState({ i: this.state.i + 1 });
}, 1000);
}
render() {
return (
<div className="container">
{this.state.name}
</div>
);
}
}
ReactDOM.render(<Layout />, document.getElementById('app'));
Every time a render is triggered, you're calling setInterval again, adding to the number of active intervals on the page.
You should perhaps make use of another lifecycle method, such as componentDidMount. You should remember to save the interval ID returned by setInterval, so that you can call clearInterval in componentWillUnmount.

Categories

Resources