I want to add a delete button to my 'Todo' component
also make a method called deleteTodo in my 'App' component
pass the deleteTodo method to the 'ToDo' component as a prop
and finally add an onClick event listener to the delete button
I've been stuck for days trying to figure this out any help would be much appreciated
my Todo.js component
import React, { Component } from 'react';
class ToDo extends Component {
render() {
return (
<li>
<input type="checkbox" checked={ this.props.isCompleted } onChange={ this.props.toggleComplete } />
<span>{ this.props.description }</span>
<button> </button>
</li>
);
}
}
export default ToDo;
the App
import React, { Component } from 'react';
import './App.css';
import ToDo from './components/ToDo.js';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{ description: 'Walk the cat', isCompleted: true },
{ description: 'Throw the dishes away', isCompleted: false },
{ description: 'Buy new dishes', isCompleted: false }
],
newTodoDescription: ''
};
}
deleteTodo() {}
handleChange(e) {
this.setState({ newTodoDescription: e.target.value })
}
handleSubmit(e) {
e.preventDefault();
if (!this.state.newTodoDescription) { return }
const newTodo = { description: this.state.newTodoDescription, isCompleted: false };
this.setState({ todos: [...this.state.todos, newTodo], newTodoDescription: '' });
}
toggleComplete(index) {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.isCompleted = todo.isCompleted ? false : true;
this.setState({ todos: todos });
}
render() {
return (
<div className="App">
<ul>
{ this.state.todos.map( (todo, index) =>
<ToDo key={ index } description={ todo.description } isCompleted={ todo.isCompleted } toggleComplete={ () => this.toggleComplete(index) } />
)}
</ul>
<form onSubmit={ (e) => this.handleSubmit(e) }>
<input type="text" value={ this.state.newTodoDescription } onChange={ (e) => this.handleChange(e) } />
<input type="submit" />
</form>
</div>
);
}
}
export default App;
Change all your event handler functions to arrow functions or bind them manually in constructor otherwise you can’t do setState or access to props inside these functions
You already have deleteTodo function declared in App.js Component so pass down this function as prop to Todo component.
Call deleteTodo function on button onClick using this.props.deleteTodo by passing description as parameter. You will use this description to remove todo from todos list in deleteTodo function
Now, when button is clicked you need to delete an item so do filter on todos state array with description
And set the newly returned todos to your state so that you will see only available todos
Here is updated code
App.js
import React, { Component } from 'react';
import './App.css';
import ToDo from './components/ToDo.js';
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: [
{ description: 'Walk the cat', isCompleted: true },
{ description: 'Throw the dishes away', isCompleted: false },
{ description: 'Buy new dishes', isCompleted: false }
],
newTodoDescription: ''
};
}
deleteTodo = description => {
const newTodos = this.state.todos.filter(todo => todo.description != description);
this.setState({
todos: newTodos
});
}
handleChange = e => {
this.setState({ newTodoDescription: e.target.value })
}
handleSubmit = e => {
e.preventDefault();
if (!this.state.newTodoDescription) { return }
const newTodo = { description: this.state.newTodoDescription, isCompleted: false };
this.setState({ todos: [...this.state.todos, newTodo], newTodoDescription: '' });
}
toggleComplete = index => {
const todos = this.state.todos.slice();
const todo = todos[index];
todo.isCompleted = todo.isCompleted ? false : true;
this.setState({ todos: todos });
}
render() {
return (
<div className="App">
<ul>
{ this.state.todos.map( (todo, index) =>
<ToDo key={ index } description={ todo.description } isCompleted={ todo.isCompleted } toggleComplete={ () => this.toggleComplete(index) } deleteTodo={this.deleteTodo} />
)}
</ul>
<form onSubmit={ (e) => this.handleSubmit(e) }>
<input type="text" value={ this.state.newTodoDescription } onChange={ (e) => this.handleChange(e) } />
<input type="submit" />
</form>
</div>
);
}
}
export default App;
Todo.js
import React, { Component } from 'react';
class ToDo extends Component {
render() {
return (
<li>
<input type="checkbox" checked={ this.props.isCompleted } onChange={ this.props.toggleComplete } />
<span>{ this.props.description }</span>
<button onClick={() => this.props.deleteTodo(this.props.description)}>Delete Todo </button>
</li>
);
}
}
export default ToDo;
Define your deleteToDo method in app component and pass it down to ToDo component as follows.
<ToDo
key={ index }
description={ todo.description }
isCompleted={ todo.isCompleted }
toggleComplete={ () => this.toggleComplete(index) }
deleteToDo={this.deleteToDo}
/>
Then inside your ToDo component you can add the handler as
<button onClick={this.props.deleteToDo}> </button>
Hope this solves your query!!
Related
there is one more error TypeError: Cannot destructure property 'handleShow' of 'object null' as it is null.
output when i consoled log is
pr
SearchModal.js:35 {username: "pr"}
SearchModal.js:38 [{…}]0: {id: "602df77cea2b563d7ceda4ac", username: "pratik", email: "pratik#gmail.com"}length: 1__proto_: Array(0)
also it is not searching when i type p its giving searc:'' and when i add prat then search : 'pra' only
Also it is not rendering username just check userdetails.map it is console logging the details but not rendering on page
import React, { Component } from 'react';
import { SearchUser } from '../services/SearchService';
import {Modal} from 'react-bootstrap';
class SearchModal extends Component {
constructor(props){
super(props);
this.state = {
show: false,
search: '',
userdetails:[]
}
this.handleShow = this.handleShow.bind(this);
this.handleClose = this.handleClose.bind(this);
this.onTextboxChangeSearch = this.onTextboxChangeSearch.bind(this);
}
handleShow() {
this.setState({ show: true })
}
handleClose(){
this.setState({ show: false })
}
async onTextboxChangeSearch(event) {
this.setState({
search: event.target.value
});
let {search,userdetails} = this.state;
console.log(search)
const data = {username:search};
console.log(data)
let SearchStatus = await SearchUser(data);
userdetails=SearchStatus.user
console.log(userdetails);
}
render() {
let {search,userdetails}= this.state;
return (
<div>
<Modal show={this.state.show} onHide={this.handleClose}>
<Modal.Header closeButton>
<Modal.Title>
<input
type="text"
placeholder="Search.."
value={search}
onChange={this.onTextboxChangeSearch}
></input>
</Modal.Title>
</Modal.Header>
<Modal.Body>
<h3>Users</h3>
<div>
<ul>
{userdetails.map(element => {
<li>{element.username}</li>
})}
</ul>
</div>
</Modal.Body>
</Modal>
</div>
)
}
}
export default SearchModal;
Dashboard
import React, { Component } from 'react';
import { Link,Redirect } from 'react-router-dom';
import UserService from "../services/userservice";
import SearchModal from './SearchModal'
export default class Dashboard extends Component{
constructor(props) {
super(props);
this.state = {
currentUser: UserService.getCurrentUser(),
isLoading:false,
};
this.logOut = this.logOut.bind(this);
this.onClick = this.onClick.bind(this);
}
logOut() {
UserService.logout()
}
SearchModalRef = ({handleShow}) => {
this.showModal = handleShow;
}
onClick = () => {
this.showModal();
}
render(){
const { currentUser ,isLoading } = this.state;
console.log(currentUser)
if (isLoading) {
return (<div><p>Loading...</p></div>);
}
if(!currentUser){
return(
<div>
<Redirect to='/login' />
</div>
)
}
else{
return(
<div>
<header>
<h1>Dashboard</h1>
{' '}
<div>
<Link to={`/dashboard/profile/:${currentUser.user._id}`}>Profile</Link>
</div>
{' '}
<div>
<Link to="/login" onClick={this.logOut}>LogOut</Link>
</div>
{' '}
<SearchModal ref={this.SearchModalRef} ></SearchModal>
<button type="button" onClick={this.onClick}>
Search
</button>
</header>
<div>
</div>
</div>
);
}
}
}
Issue
it is not searching when i type p its giving searc:'' and when i add
prat then search : 'pra' only
React state updates are asynchronous and batch processed between render cycles. This means when you enqueue a state update it won't be available until the next render cycle. Any further references to state in the same function will be the state value from the current render cycle.
async onTextboxChangeSearch(event) {
this.setState({
search: event.target.value // <-- next state
});
let {search,userdetails} = this.state; // <-- still current state!
console.log(search)
const data = {username:search};
console.log(data)
let SearchStatus = await SearchUser(data);
userdetails=SearchStatus.user
console.log(userdetails);
}
Solution
I suggest factoring out the search logic into its own function to be called by the componentDidUpdate lifecycle methods when state updates.
onTextboxChangeSearch(event) {
const { value } = event.target;
this.setState({
search: value // <-- (1) update state
});
}
searchForUser = async () => { // <-- (3) refactored search function
const { search, userdetails } = this.state;
const data = { username: search };
const { user } = await SearchUser(data);
this.setState(prevState => ({
userdetails: [...prevState.userdetails, user], // append user
}));
}
componentDidUpdate(prevProps, prevState) {
if (prevState.search !== this.state.search) {
this.searchForUser(); // <-- (2) search state updated, do search for user
}
}
So, I have three components(Search, Pages, HanddlesApi) plus App.js and I'm passing props around via functions to other child components with no problem.
The Search component passes it's state of userInput to HandleApi component and updates the api using componentDidUpdate. (this works great, np here).
I added the Pages component to update the api's page number so that the user can cycle through pages of content. This works, but with issues. The user can do a search and cycle though the pages, but if they enter a new query, they will land on the same page number of the new query. For example, If
I searched "ducks" and clicked to the next page(2). Then did a search for "dogs" they would land on page two of "dogs"
So my question is how do I reset state for my Pages component only when a user enters a new query?
I saw that componentWillReceiveProps is being deprecated, so I can't use that.
getDerivedStateFromProps seemed like it might be a good idea, but from what I read it should only be used in rare cases.
So, the two most likely options seemed to be, use componentDidUpdate in a way I don't understand or use key?
Overall I'm just confused on what to do
In my HanddlesApi Component I'm passing the follwoing into the API:
q: this.props.inputValue ? this.props.inputValue : 'news',
page: this.props.pageNum ? this.props.pageNum: 0
then..
componentDidMount() {
this.fetchNews()
}
componentDidUpdate(prevProps, prevState) {
if (this.props.inputValue !== prevProps.inputValue || this.props.pageNum !== prevProps.pageNum) {
this.setState({
news: []
}, this.fetchNews);
}
}
Then in my Pages Component, I have
import React, { Component } from 'react'
class Pages extends Component {
constructor(props) {
super(props)
this.state = {
nextPage: 1,
prevPage: 0
}
}
handleNextClick = () => {
this.setState({
nextPage: this.state.nextPage + 1,
})
}
handlePrevClick = () => {
this.setState({
prevPage: this.state.prevPage - 1,
})
}
render() {
return (
<div className='pageNav'>
<button className="PrevButton" onClick={() => {
this.handlePrevClick()
this.props.onNextButtonClick(this.state.prevPage)
}}>Previous </button>
<button className="nextButton" onClick={() => {
this.handleNextClick()
this.props.onNextButtonClick(this.state.nextPage)
}}>Next </button>
</div>
)
}
}
export default Pages
Search Component
import React, { Component } from 'react';
class SearchBar extends Component {
constructor(props) {
super(props)
this.state = {
inputValue: ""
}
}
handleChange = (e) => {
this.setState({
inputValue: e.target.value
})
}
handleSubmit = (e) => {
e.preventDefault()
this.props.onSubmittedSearch(this.state.inputValue)
}
render() {
//{this.props.onSubmittedSearch(this.state.inputValue)}
return (
<section>
<form onSubmit={this.handleSubmit}>
<label htmlFor="searching"></label>
<input type="text" placeholder="Search Something" value={this.state.inputValue} onChange={this.handleChange} />
<button type="submit">Search </button>
</form>
</section>
)
}
}
export default SearchBar
App.js
class App extends Component {
constructor(props) {
super(props)
this.state = {
inputValue: null,
pageNum: 1
}
}
// used to pass props from SearchBar to NewsList
onSubmittedSearch = (inputValue) => {
this.setState({
inputValue: inputValue
})
}
onNextButtonClick = (pageNum) => {
this.setState({
pageNum: pageNum
})
}
render() {
return (
<main>
<SearchBar onSubmittedSearch={this.onSubmittedSearch} />
<NewsList inputValue={this.state.inputValue} pageNum={this.state.pageNum} />
<Pages onNextButtonClick={this.onNextButtonClick} />
<Footer />
</main>
)
}
}
export default App;
You should let App in charge of changing and holding the current page number. So you can reset it each time your search component submit. Here is a working exemple:
class Pages extends React.Component {
render() {
return (<div className='pageNav'>
<button disabled={this.props.page <= 1} className="PrevButton" onClick={this.props.onPrevButtonClick}>Previous
</button>
<span>{this.props.page}</span>
<button className="nextButton" onClick={this.props.onNextButtonClick}>Next
</button>
</div>)
}
}
class SearchBar extends React.Component {
constructor(props) {
super(props)
this.state = {
inputValue: ""
}
}
handleChange = (e) => {
this.setState({inputValue: e.target.value})
}
handleSubmit = (e) => {
e.preventDefault()
this.props.onSubmittedSearch(this.state.inputValue)
}
render() {
//{this.props.onSubmittedSearch(this.state.inputValue)}
return (<section>
<form onSubmit={this.handleSubmit}>
<label htmlFor="searching"></label>
<input type="text" placeholder="Search Something" value={this.state.inputValue} onChange={this.handleChange}/>
<button type="submit">Search
</button>
</form>
</section>)
}
}
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
inputValue: null,
pageNum: 1
}
}
// used to pass props from SearchBar to NewsList
onSubmittedSearch = (inputValue) => {
this.setState({inputValue: inputValue, pageNum: 1})
}
onNextButtonClick = () => {
this.setState(state => ({
pageNum: state.pageNum + 1
}))
}
onPrevButtonClick = (pageNum) => {
this.setState(state => ({
pageNum: Math.max(state.pageNum - 1, 1)
}))
}
render() {
return (<main>
<SearchBar onSubmittedSearch={this.onSubmittedSearch}/>
<Pages onNextButtonClick={this.onNextButtonClick} onPrevButtonClick={this.onPrevButtonClick} page={this.state.pageNum}/>
</main>)
}
}
ReactDOM.render(<App/>, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
I am creating a todo list where when the user clicks the checkbox "complete" that is next to the todo item, it appears in the complete component however there is a duplicate of that item that is being added as well and i am also having an issue trying to have the checkbox not appear in the completed component...
When a user creates a new todo it appears in the active component first and it has a checkbox next to it called completed and when the user clicks the checkbox it appears in the completed component
import React from 'react';
import Active from './Components/Active';
import Completed from './Components/Completed';
import Todoform from './Components/Todoform';
import './App.css';
class App extends React.Component {
state = {
items: [],
task: '',
id: 0,
completedItems: []
}
handleInput = (event) => {
this.setState({
task: event.target.value
})
}
handleSubmit = (event) => {
event.preventDefault()
const newTask = {
id: this.state.id,
title: this.state.task
}
const updatedItems = [...this.state.items, newTask]
this.setState({
items: updatedItems,
task: '',
id: this.state.id + 1
})
}
handleComplete = (newTask) => {
this.setState({completedItems: [...this.state.items, newTask]})
//console.log(this.state.items)
}
render() {
return (
<div id="main-content">
<h1>Task Lister</h1>
<Todoform
handleChange={this.handleInput}
handleSubmit={this.handleSubmit}
task={this.state.task}
/>
<Active
items={this.state.items}
handleComplete={this.handleComplete}
/>
<Completed
completedItems={this.state.completedItems}
/>
</div>
)
}
}
export default App;
import React from 'react'
class Todo extends React.Component{
state = {
checked: false
}
handleCheck = () => {
this.setState({
checked: !this.state.checked
})
}
handleClick = () => {
this.props.handlecompletedList(this.props.title)
}
render(){
const { title } = this.props
return (
<div className="ui checked checkbox">
<input type="checkbox" checked={this.state.checked} onChange={this.handleCheck}
onClick={this.handleClick}/>
<label>Completed {title}</label>
</div>
)
}
}
export default Todo;
import React from 'react'
import Todo from './Todo'
const Active = (props) => {
const { items, handleComplete } = props
return(
<div id="activeList">
<h2 className="position">Active</h2>
<ul id="tasks">
{
items.map(item => {
return(
<Todo key={item.id} handlecompletedList={handleComplete} title={item.title}/>
)
})
}
</ul>
</div>
)
}
export default Active;
import React from 'react'
import Todo from './Todo'
const Completed = (props) => {
const { completedItems } = props
return(
<div id="completedList">
<h2 className="position">Completed</h2>
<ul id="tasks">
{
completedItems.map(item => {
return(
<Todo key={item.id} title={item.title}/>
)
})
}
</ul>
</div>
)
}
export default Completed
import React from 'react';
class Todoform extends React.Component {
render(){
const {task, handleChange, handleSubmit} = this.props;
return(
<form onSubmit={handleSubmit}>
<label>Task description:</label>
<input type="text" name="name" placeholder="description" value={task} onChange={handleChange}/>
<button>Create New Task</button>
</form>
)
}
}
export default Todoform;
To hide the checkbox next to completed items you need to use Conditional Rendering. An example would be to add a prop IsCompleted to your component and use it when rendering html like this:
{this.props.isCompleted &&
<input
type="checkbox"
checked={this.state.checked}
onChange={this.handleCheck}
onClick={this.handleClick}/>
}
The duplicate item issue is probably because you use this.state.items in your handleComplete method instead of using this.state.completedItems if this is not the issue, would you mind sharing the code for the Todoform component as well?
EDIT: The item duplicates because when the handleComplete is called it copies this.state.items to the list and adds the one that you clicked on.
You should use this.state.completedItems in the handleComplete, also you are currently only sending and appending the title in the handleComplete method, you should be appending an object that has a title. The solution would be to update your handleClick method to this and update handleComplete to use this.state.completedItems:
handleClick = () => {
this.props.handlecompletedList({
title: this.props.title
});
};
Problem
It's not showing the elements within the item. It doesn't render anything at the moment.
List.js
import React from 'react';
const List = props => (
<div>
{
props.items.map((item, index) => {
return <div key={index}>
<h1>{item.name}</h1>
<p>{item.term}</p>
</div>
})}
</div>
);
export default List;
App.js
import React, {Component} from 'react'
import './App.css'
import List from './List';
class App extends Component {
constructor(props) {
super(props);
this.state = {
term: '',
name: '',
items: []
};
}
onChange = (event) => {
const { name, value } = event.target;
this.setState({ [name]: value });
}
onSubmit = (event) => {
event.preventDefault();
this.setState({
term: '',
name: '',
items: [
...this.state.items,
this.state.term,
this.state.name
]
});
}
render() {
const { term, name, items } = this.state;
return (
<div>
<form className="App" onSubmit={this.onSubmit}>
<input name="term" value={this.state.term} onChange={this.onChange}/>
<input name="name" value={this.state.name} onChange={this.onChange}/>
<button>Submit</button>
</form>
<List items={this.state.items} />
</div>
);
}
}
Issue was in onSubmit, you need to convert to object and than add
onSubmit = event => {
event.preventDefault();
this.setState({
term: "",
name: "",
items: [...this.state.items, { term: this.state.term, name: this.state.name}]
});
setTimeout(() => { console.log(this.state.items) }, 0)
};
https://codesandbox.io/s/p7p128w7mx
Hello guys I started learning react recently and I'm having some issues. I'm trying to make simple react app, one of the components I'm making is stopwatch.
The issue I'm having is that when I start typing in my input for stopwatch the timer resets.
Here is my main component:
import React, { Component } from 'react';
import Clock from '../components/Clock.jsx';
import Stopwatch from '../components/Stopwatch.jsx';
import '../css/App.css';
import { Form, FormControl, Button } from 'react-bootstrap';
class App extends Component {
constructor(props) {
super(props);
this.state = {
deadline: 'December 25, 2018',
newDeadline: '',
timer: 60,
newTimer: '',
};
}
changeDeadline() {
this.setState({
deadline: this.state.newDeadline,
});
}
changeTimer() {
this.setState({
timer: this.state.newTimer,
});
}
render() {
return (
<div className='app'>
<div className='app_title'>
Countdown to {this.state.deadline}
</div>
<Clock
deadline = {this.state.deadline}
/>
<Form inline >
<FormControl
className="deadline_input"
type="text"
placeholder="New date"
onChange={event => this.setState({newDeadline: event.target.value})}
onKeyPress={event => {
if (event.key === 'Enter') {
event.preventDefault();
this.changeDeadline();
}
}}
/>
<Button onClick={() => this.changeDeadline()} >
Submit
</Button>
</Form>
<div className="stopwatch_title">
Stopwatch from {this.state.timer} seconds
</div>
<Form inline>
<FormControl
className="stopwatch_input"
type="text"
placeholder="Enter time"
onChange={event => this.setState({newTimer: event.target.value})}
onKeyPress={event => {
if (event.key === 'Enter') {
event.preventDefault();
this.changeTimer();
}
}}
/>
<Button onClick={() => this.changeTimer()} >
Submit
</Button>
</Form>
<Stopwatch
timer = {this.state.timer}
/>
</div>
);
}
}
export default App;
and my stopwatch component:
import React, {Component} from 'react';
import '../css/App.css';
import { Button } from 'react-bootstrap';
class Stopwatch extends Component {
constructor(props) {
super(props);
this.state = {
stopwatch: props.timer,
};
this.decrementer = null;
}
componentWillReceiveProps(nextProps) {
clearInterval(this.decrementer);
this.timerCountdown(nextProps.timer);
}
timerCountdown(newTimer) {
// First we update our stopwatch with new timer
this.setState({
stopwatch: newTimer
});
}
startTimer() {
// Then we decrement stopwatch by 1 every second
this.decrementer = setInterval( () => {
this.setState({
stopwatch: this.state.stopwatch -1,
});
},1000);
}
componentDidUpdate() {
if (this.state.stopwatch < 1) {
clearInterval(this.decrementer);
alert('Countdown finished');
}
}
render() {
return(
<div>
<Button onClick={() => this.startTimer()} >
Start
</Button>
<div className="stopwatch"> {this.state.stopwatch} </div>
</div>
);
}
}
export default Stopwatch;
Here is gif of the problem https://imgur.com/9xqMW96
As you can see my timer resets after I start typing in input. I would like for it to reset only when user presses enter key or uses submit button.
I've tried doing something like this:
<input value={this.state.newTimer} onChange={evt => this.updateInputValue(evt)}/>
updateInputValue: function(evt) {
this.setState({
newTimer: evt.target.value
});
}
but it didn't work for me.
You can see code in action here: https://karadjordje.github.io/countdown-stopwatch-react/
You are stopping the interval on each new prop that the component receives.
You can either handle the time in a local state or explicitly pass the proper new values from the parent.
I've made a small basic example so you can see the data flow and how each event is responsible for a small portion of the data.
Hope that helps.
class App extends React.Component {
state = {
startTime: 5,
currentTime: 5,
textInput: ''
}
startTimer = () => {
if (this.interval) {
clearInterval(this.interval);
}
this.interval = setInterval(() => {
this.setState(prev => {
if (prev.currentTime === 0) {
this.stopTimer();
return { ...prev, currentTime: prev.startTime };
} else {
return {
...prev,
currentTime: prev.currentTime - 1
}
}
})
}, 1000)
}
stopTimer = () => {
clearInterval(this.interval);
}
updateInput = ({ target }) => {
this.setState(prev => ({ textInput: target.value }));
}
setStartTime = () => {
this.stopTimer();
this.setState(({ textInput }) => ({ startTime: textInput, currentTime: textInput, textInput: '' }));
}
render() {
const { currentTime, textInput } = this.state;
return (
<div >
<div>{currentTime}</div>
<button onClick={this.startTimer}>Start timer</button>
<div>
<input placeholder="Enter start time" value={textInput} onChange={this.updateInput} />
<button onClick={this.setStartTime}>Set Start time</button>
</div>
</div>
);
}
}
ReactDOM.render(<App />, 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>
I have updated my code.
Instead of using componentWillUpdate I'm using componentDidUpdate and this is my code for it:
componentDidUpdate(prevProps) {
console.log('componentDidUpdate', this.props, prevProps);
if (prevProps.timer !== this.props.timer) {
this.updateTimer(this.props.timer);
clearInterval(this.decrementer);
}
if (this.state.stopwatch < 1) {
clearInterval(this.decrementer);
alert('Countdown finished');
}
}
Basically I'm only updating timer is previous timer is different from current.