I'm trying to change the state.time after timer off, but I always get an error: TypeError: this.state.time.toLocaleTimeString is not a function. What is the problem is? Maybe anyone know...
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import './index.css';
class Demoss extends React.Component {
constructor(props) {
super(props);
this.state = {
time: new Date()
};
this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
this.timerId = setInterval(() => this.setState({
time: new Date()
}), 1000);
}
componentWillUnmount() {
clearInterval(this.timerId);
}
handleClick() {
clearInterval(this.timerId);
this.setState((prevState) => {
return {time: prevState.time + 12}
});
}
render() {
if (this.state.time.toString().match(/\d\d:\d\d:\d\d/g)) {
return (
<div>
<p>{this.state.time.toLocaleTimeString()}</p>
<p>{this.timerId}</p>
<button onClick={this.handleClick}>clearTimer</button>
</div>
);
} else {
return (
<div>
<p>{this.state.time}</p>
<p>{this.timerId}</p>
<button onClick={this.handleClick}>clearTimer</button>
</div>
);
}
}
}
ReactDOM.render(
<Demoss />,
document.getElementById('root'));
It's because you are adding 12 to your date, thereby converting it to a number. You can increment your date like so:
Date.prototype.addHours = function(h){
this.setHours(this.getHours()+h);
return this;
}
this.setState((prevState) => {
return {time: prevState.time.addHours(12) }
});
Fiddle
Related
I am having an issue where I'm trying to pass a function(updateEvents) via props from my App.js file to a NumberOfEvents.js file. I passed the same function to another component with no issues. However, when I try on the NumberOfEvents file, I get the following error:
Error image
Please help!!!
Here is the Parent:
import React, { Component } from 'react';
import EventList from './EventList';
import CitySearch from './CitySearch';
import NumberOfEvents from './NumberOfEvents';
import { extractLocations, getEvents } from './api';
import './nprogress.css';
import './App.css';
class App extends Component {
state = {
events: [],
locations: [],
numberOfEvents: 32
}
componentDidMount() {
this.mounted = true;
getEvents().then((events) => {
if (this.mounted) {
this.setState({
events: events.slice(0, this.state.numberOfEvents),
locations: extractLocations(events)
});
}
});
}
componentWillUnmount() {
this.mounted = false;
}
updateEvents = (location, eventCount) => {
this.mounted = true;
getEvents().then((events) => {
const locationEvents = (location === 'all')
? events
: events.filter((event) => event.location === location);
this.setState({
events: locationEvents,
numberOfEvents: eventCount,
});
});
};
render() {
return (
<div className="App">
<CitySearch
locations={this.state.locations} updateEvents={this.updateEvents} />
<EventList
events={this.state.events} />
<NumberOfEvents
numberOfEvents={this.state.numberOfEvents}
updateEvents={this.updateEvents} />
</div>
);
}
}
export default App;
And here is the Child:
import React, { Component } from 'react';
class NumberOfEvents extends Component {
state = {
numberOfEvents: 32
}
handleChange = (event) => {
const value = event.target.value;
this.setState({
numberOfEvents: value,
});
this.props.updateEvents('', value);
};
render() {
return (
<input
className="number"
value={this.state.numberOfEvents}
onChange={this.handleChange} />
)
}
}
export default NumberOfEvents;
Im not sure this will help ...In Your Parent Component , inside return statement when passing the updateEvents Prop, try passing it as arrow function like this ....
updateEvents={ () => this.updateEvents() } />
try adding a constructor to the child component
constructor(props) {
super(props);
this.state = {
numberOfEvents: 32
}
}
this is my showdate.js - >
import React, { Component } from "react";
class Showdate extends Component {
componentWillMount() {
setInterval(1000);
}
render() {
return (
<div>
<h1>Welcome to GeeksforGeeks!</h1>
<h2>{new Date().toLocaleTimeString()}</h2>
</div>
);
}
}
export default Showdate;
and rendering through index.js as ->
import React from "react";
import ReactDOM from "react-dom";
import Showdate from "./showDate";
const rootElement4 = document.getElementById("root4");
console.log(<Showdate />);
ReactDOM.render(<Showdate />, rootElement4);
time is getting displayed but it is not refresshing by one sec as it should acc to setinterval(1000)
You must do something like this:
constructor(props){
super(props);
this.state = {
myTime: new Date() //Initialize your state
}
}
componentDidMount() { //Use componentDidMount instead of componentWillMount
this.myInterval = setInterval(()=>this.tick(), 1000); //Provide a callback to setInterval
}
tick(){
this.setState({myTime: new Date()})
}
componentWillUnmount() {
clearInterval(this.myInterval); //You must clear interval when the component is unmounted; otherwise it could lead to memory leakage
}
Then Use myTime in your JSX
<h2>{this.state.myTime.toLocaleTimeString()}</h2>
you can this :
this.timerChronoId = setInterval(() => {
this.setState({
time: (this.state.time + 1)
});
}, 1000);
you can use this.timerChronoId after to pause the timer by calling :
clearInterval(this.timerChronoId);
The function setInterval is taking a callback function and the timeout. So, you have to implement it as follows. Plus, you should clear the interval before your component is unmounted.
import React, { Component } from "react";
class Showdate extends Component {
constructor(props) {
super(props);
this.state = { date: new Date() }
}
componentDidMount() {
this.timer = setInterval(() => this.tick(), 1000)
}
componentWillUnmount() {
clearInterval(this.timer)
}
tick() {
this.setState({ date: new Date() })
}
render() {
return (
<div>
<h1>Welcome to GeeksforGeeks!</h1>
<h2>{this.state.date.toLocaleTimeString()}</h2>
</div>
);
}
}
export default Showdate;
In my react app I am using a timer component. I want this component to run in the background and call a parent function after a certain time. The code is giving error. My code is
parent component
import React, { Component } from 'react';
import Timer from './timer';
class Parent extends Component {
finish(){
console.log('fininsh')
}
render() {
return (
<div>
<Timer data={this.finish.bind(this)} />
</div>
);
}
}
export default Parent;
timer component
import React, { Component } from 'react';
class Timer extends Component {
constructor(props){
super(props);
this.state = {
fin: false
}
}
componentDidMount(){
this.myInterval = setInterval(() => {
this.setState({fin: true})
}, 10000);
}
childfinish = () => {
this.props.data.finish
}
render() {
const {fin} = this.state;
if(fin){
return(
<div>
{this.childfinish};
</div>
)
} else {
return (
<div>
<h1>Counting...</h1>
</div>
)
}
}
}
export default Timer;
the error is
Expected an assignment or function call and instead saw an expression
data prop does not contain function finish().
Remove {this.childfinish} from render() and
componentDidMount(){
this.myInterval = setInterval(() => {
this.setState({fin: true})
this.props.data();
}, 10000);
}
Found the solution
parent component
import React, { Component } from 'react';
import Timer from './timer';
class Parent extends Component {
finish(){
console.log('fininsh')
}
render() {
return (
<div>
<Timer data={{callfinish : this.finish.bind(this)}} />
</div>
);
}
}
export default Parent;
Child Component
import React, { Component } from 'react';
class Timer extends Component {
constructor(props){
super(props);
this.state = {
fin: false
}
}
componentDidMount(){
this.myInterval = setInterval(() => {
this.setState({fin: true})
}, 10000);
}
childfinish = () => {
clearInterval(this.myInterval);
this.props.data.callfinish();
}
render() {
const {fin} = this.state;
if(fin){
this.childfinish();
return (
<div></div>
)
} else {
return (
<div>
<h1>Counting...</h1>
</div>
)
}
}
}
export default Timer;
The parent function will run after 10 seconds.
Here is the component TimeDisplay where I have the function handleTimer.
import React, {Component} from "react";
import format from './formatTime';
class TimeDisplay extends Component {
constructor(props) {
super(props);
this.state = {
time: 0,
on: false,
}
}
handleTimer = () => {
if (this.state.on) {
clearInterval(this.timer);
} else {
this.timer = setInterval(() => {
this.setState({time: ++this.state.time})
console.log("timer running");
}, 10)
}
this.setState({on: !this.state.on})
}
render() {
var time = format(this.state.time);
return <div>
<div className="controls">
<button onClick={this.handleTimer}>Run</button>
</div>
<h1 className="display-time">{time}</h1>
</div>
}
}
export default TimeDisplay;
Now, what I'd like to do is create a button that behaves exactly like the one in render(), but in another component. How do I do it?
If you have two components then keep the button in one component and import into second component and pass handleTimer functions as props to that component below i am giving example
import React, {Component} from "react";
import format from './formatTime';
class ButtonAction extends Component {
constructor(props) {
super(props);
this.state = {
time: 0,
on: false,
}
}
handleTimer=()=>{
this.props.handleTimer();
}
render() {
var time = format(this.state.time);
return <div>
<div className="controls">
<button onClick={this.handleTimer}>Run</button>
</div>
<h1 className="display-time">{time}</h1>
</div>
}
}
export default ButtonAction ;
import NewComponent in TimeDisplay component
import NewComponent from "./ButtonAction ";
import React, {Component} from "react";
import format from './formatTime';
class TimeDisplay extends Component {
constructor(props) {
super(props);
this.state = {
time: 0,
on: false,
}
}
handleTimer = () => {
if (this.state.on) {
clearInterval(this.timer);
} else {
this.timer = setInterval(() => {
this.setState({time: ++this.state.time})
console.log("timer running");
}, 10)
}
this.setState({on: !this.state.on})
}
render() {
var time = format(this.state.time);
return <div>
<NewComponent handleTimer ={this.handleTimer} />
</div>
}
}
export default TimeDisplay;
So I keep div element in my state. I want to change it's className in response to onClick event. I know I could do it with event.target.className but the code below is only the sample of a biggest application and it's not possible to use it there. As a resultant from changeClass function I get
"TypeError: Cannot assign to read only property 'className' of object '#'".
So I wonder is there any other way to do it?
import React, { Component } from "react";
import "./styles/style.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
myDiv: [
<div
id="firstDiv"
key={1}
className={"first"}
onClick={this.changeClass}
/>
]
};
}
changeClass = () => {
this.setState(prevState => {
return { myDiv: (prevState.myDiv[0].props.className = "second") };
});
};
render() {
return <div>{this.state.myDiv.map(div => div)}</div>;
}
}
export default App;
Don't put your jsx in state. only add className and state and onChangeClass use this.stateState to update className.
import React, { Component } from "react";
import "./styles/style.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
className:"first"
};
}
changeClass = () => {
this.setState({ classNmae: "two" });
};
render() {
return <div>
<div
id="firstDiv"
className={this.state.className}
onClick={this.changeClass}
/>
</div>;
}
}
export default App;
there's a simpler option try this:
import React, { Component } from "react";
import "./styles/style.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
className: "first"
};
}
changeClass = () => {
this.setState({className: "second"});
};
render() {
return <div
id="firstDiv"
className={this.state.className}
onClick={this.changeClass}>
</div>;
}
}
export default App;
You can use Hooks if you use a React version upper than 16.8
import React, { useState } from "react"
import "./styles/style.css"
const App = () => {
const [myClass, setMyClass] = useState("first")
const changeClass = () => {
setMyClass("second")
}
render() {
return <div
id="firstDiv"
className={myClass}
onClick={changeClass}>
</div>;
}
}
export default App