Calling parent function after setInterval timeout - javascript

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.

Related

I am not able to set interval in my react app

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;

How to run function of a Component from a button of another Component?

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;

How to change className?

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

Can i pass component state to HoC?

Is there any way to send data from the component's state to HoC?
My component
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
contructor() {
super();
this.state = {
error: true
}
}
render() {
return (
<div> Test </div>
)
}
};
export default withHandleError(SendScreen)
My HoC component:
import React, { Component } from 'react';
import { ErrorScreen } from '../../ErrorScreen';
import { View } from 'react-native';
export default Cmp => {
return class extends Component {
render() {
const { ...rest } = this.props;
console.log(this.state.error) //// Cannot read property 'error' of null
if (error) {
return <ErrorScreen />
}
return <Cmp { ...rest } />
}
}
}
Is there any way to do this?
Is the only option is to provide props that must come to the SendScreen component from outside??
A parent isn't aware of child's state. While it can get an instance of a child with a ref and access state, it can't watch on state updates, the necessity to do this indicates design problem.
This is the case for lifting up the state. A parent needs to be notified that there was an error:
export default Cmp => {
return class extends Component {
this.state = {
error: false
}
onError() = () => this.setState({ error: true });
render() {
if (error) {
return <ErrorScreen />
}
return <Cmp onError={this.onError} { ...this.props } />
}
}
}
export default withHandleError(data)(SendScreen)
In data you can send the value you want to pass to HOC, and can access as prop.
I know I answer late, but my answer can help other people
It is very easy to do.
WrappedComponent
import React, {Component} from 'react';
import PropTypes from 'prop-types';
import HocComponent from './HocComponent';
const propTypes = {
passToHOC: PropTypes.func,
};
class WrappedComponent extends Component {
constructor(props) {
super(props);
this.state = {
error: true,
};
}
componentDidMount() {
const {passToHOC} = this.props;
const {error} = this.state;
passToHOC(error); // <--- pass the <<error>> to the HOC component
}
render() {
return <div> Test </div>;
}
}
WrappedComponent.propTypes = propTypes;
export default HocComponent(WrappedComponent);
HOC Component
import React, {Component} from 'react';
export default WrappedComponent => {
return class extends Component {
constructor() {
super();
this.state = {
error: false,
};
}
doAnything = error => {
console.log(error); //<-- <<error === true>> from child component
this.setState({error});
};
render() {
const {error} = this.state;
if (error) {
return <div> ***error*** passed successfully</div>;
}
return <WrappedComponent {...this.props} passToHOC={this.doAnything} />;
}
};
};
React docs: https://reactjs.org/docs/lifting-state-up.html
import React, { Component } from 'react';
import withHandleError from './withHandleError';
class SendScreen extends Component {
contructor() {
super();
this.state = {
error: true
}
}
render() {
return (
<div state={...this.state}> Test </div>
)
}
};
export default withHandleError(SendScreen)
You can pass the state as a prop in your component.

Function passed through props shown non-defined

I have got three components Topicscreen, Listview, Listrow. I am passing the function renderrow, and two other properties defined in my
Topicscreen to Listview.
Now when i call func in Listview, the props are passed to Listrow as defined in renderrow function, but the onRowclick function which is being passed to Listrow is undefined when i checked it in Listrow.
How to solve this error and pass onRowclick as a function to Listrow?
Topicscreen.js
class Topicscreen extends Component {
constructor() {
super();
this.onRowClick = this.onRowClick.bind(this);
}
componentDidMount() {
this.props.dispatch(topicaction.Fetchtopics());
}
renderLoading() {
return <p>Loading...</p>;
}
renderrow(rowid, topic) {
//const selected = this.props.checkselection[rowid]
const selected = "";
return (
<Listrow selected={selected} clicking={this.onRowClick} rowid={rowid}>
<h3>{topic.title}</h3>
<p>{topic.description}</p>
</Listrow>
);
}
onRowClick(rowid) {
this.props.dispatch(topicaction.selectedchoice(rowid));
}
render() {
if (!this.props.topicsByurl) return this.renderLoading();
return (
<div className="TopicsScreen">
Hi I am topic screen
<h1>Choose any three of the below topics</h1>
<Listview
rowid={this.props.topicsurlArray}
row={this.props.topicsByurl}
func={this.renderrow}
/>
</div>
);
}
}
Listview.js
import React, { Component } from "react";
import _ from "lodash";
export default class Listview extends Component {
constructor() {
super();
this.show = this.show.bind(this);
}
show(rowid) {
return this.props.func(rowid, _.get(this.props.row, rowid));
}
render() {
console.log("props in listview", this.props);
return (
<div>
<ul>{_.map(this.props.rowid, this.show)}</ul>
</div>
);
}
}
Listrow.js
import React, { Component } from "react";
export default class Listrow extends Component {
clicking() {
this.props.clicking(this.props.rowid);
}
render() {
console.log("list row called");
console.log("listrow props", this.props);
const background = this.props.selected ? "#c0f0ff" : "#fff";
return (
<div style={{ background }} onClick={this.clicking.bind(this)}>
{this.props.children}
</div>
);
}
}
You also need to bind your renderrow method in the Topicscreen constructor, or this.onRowClick inside of renderrow will not be what you expect.
class Topicscreen extends Component {
constructor(props) {
super(props);
this.onRowClick = this.onRowClick.bind(this);
this.renderrow = this.renderrow.bind(this);
}
// ...
}

Categories

Resources