Input change resets timer - reactjs

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.

Related

How can I make the text area empty after I click the submit button?

How can I make the text area empty after I click the submit button??
Im trying to create a simple form submit in react. Can you please tell me how can i make the text area empty after I click the Submit button. This is my problem.
This is my App.js code:
import React, { Component } from 'react'
import Textarea from "./Textarea";
import Button from "./Button";
export class App extends Component {
constructor(){
super();
this.state = {
Tinput: '',
// Ninput:'',
submit: ''
}
}
changeHandle = (event) => {
this.setState({
Tinput: event.target.value
})
}
submitHandle = (event) => {
event.preventDefault();
this.setState({
submit: this.state.Tinput
})
}
resetHandle = (event) => {
event.preventDefault();
this.setState(
{submit: ''}
)
}
// handleKeypress = (event) => {
// if (event.keyCode === 'Enter') {
// this.submitHandle();
// }
// }
render() {
return (
<div>
<div>
<Textarea changeHandle={this.changeHandle} change={this.state.Tinput}/>
<Button action={this.submitHandle} name="submit"/>
<Button action={this.resetHandle} name="Reset" />
</div>
<p>{this.state.submit}</p>
</div>
)
}
}
export default App
This is my Textarea.js code:
import React from 'react'
const Textarea = (props) => {
return (
<div>
<textarea
type="text"
onChange={props.changeHandle}
// onKeyPress={this.handleKeypress}
value={props.change}
className="form-control"
id="exampleFormControlTextarea1" rows="3"
placeholder='write something here'
/>
</div>
);
}
export default Textarea;
This is my button.js code:
import React from 'react'
const Button = (props) => {
return (
<div>
<button type="submit" className="btn btn-primary" onClick={props.action}>{props.name}</button>
</div>
);
}
export default Button;
You can set it as empty in submit function
submitHandle = (event) => {
event.preventDefault();
this.setState({
submit: this.state.Tinput,
Tinput:""
})
}
Try this :
submitHandle = (event) => {
event.preventDefault();
this.setState({
submit: this.state.Tinput,
Tinput: '',
})
}

How to "dynamically add/ edit/cancel/ the textarea" in reactjs

As, I am new to react I don't know how to perform dynamic add and edit and cancel operations on the textarea. I have dynamic array , i want to perform edit and cancel operations for every textarea individually . If I click on a edit button the mouse cursor should point to the specific textbox, and it should turn into editable mode . If, I click on cancel button the specific textarea should turn into non-editable mode. codesandboxdemo please Run the code in codesandox and give me the solution
index.js
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
const rootElement = document.getElementById("root");
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
rootElement
);
App.js
import React, { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
count: [],
disabled: false
};
this.newText = {};
this.handleEdit = this.selectText.bind(this);
}
handleCancel(e,index) {
this.setState({disabled:true})
}
handleRemove(index)
{
this.state.count.splice(index,1)
this.setState({count: this.state.count})
}
selectText(e, index) {
newText = this.state.count[index];
console.log(newText);
this.newText.select();
}
add(e) {
this.setState({ count: [...this.state.count, ""] ,disabled:false});
}
handleChange(e, index) {
this.state.count[index] = e.target.value;
this.setState({ count: this.state.count });
}
render() {
return (
<div>
<label>Enter the text</label>
{this.state.count.map((counts, index) => {
return (
<div key={index}>
<input
ref={(newText) => (this.newText = newText)}
onChange={(e) => this.handleChange(e, index)}
value={counts}
disabled = {(this.state.disabled)? "disabled" : ""}
/>
<button onClick={(e) => this.handleEdit(e,index)}>Edit</button>
<button onClick={() => this.handleRemove(index)}>Remove</button>
<button onClick = {(e) =>this.handleCancel(e,index)}> cancel </button>
</div>
);
})}
<button onClick={(e) => this.add(e)}> Add</button>
</div>
);
}
}
export default App;
.App {
font-family: sans-serif;
text-align: center;
}
`]2
I just tried doing it this way for you. This is not a complete answer (just to make sure I don't spoon-feed you, but this is a possible approach). Tell me if this works?
import React, { useState } from "react";
import "./styles.css";
const App = () => {
const [Value, setValue] = useState("");
const [EditMode, setEditMode] = useState(false);
const toggleEditMode = () => setEditMode(!EditMode);
return EditMode ? (
<input
type="text"
value={Value}
onChange={(e) => setValue(e.target.value)}
onBlur={toggleEditMode}
/>
) : (
<span onClick={toggleEditMode}>{Value}</span>
);
};
export default App;
Click and it will make it editable. Come out and it shows updated value.
CodeSandbox: https://c4fog.csb.app/
Here is full working code of App.js
import React, { Component } from "react";
class App extends Component {
constructor() {
super();
this.state = {
count: [],
disabled: [],
};
this.references = []
}
handleRef(r, index) {
this.references[index] = r
}
handleCancel(e,index) {
const { disabled } = this.state;
disabled[index] = true
this.setState({ disabled })
}
handleRemove(index)
{
this.state.count.splice(index,1)
this.setState({count: this.state.count})
}
handleEdit(e, index) {
const { disabled } = this.state;
disabled[index] = false
this.setState({ disabled }, () => {
this.references[index].focus()
})
}
add(e) {
this.setState({ count: [...this.state.count, ""] });
}
handleChange(e, index) {
const { count } = this.state;
count[index] = e.target.value;
this.setState({ count });
}
render() {
const { disabled, count } = this.state
return (
<div>
<label>Enter the text</label>
{count.map((counts, index) => {
return (
<div key={index}>
<input
ref={(newText) => this.handleRef(newText, index)}
onChange={(e) => this.handleChange(e, index)}
value={counts}
disabled ={disabled[index]}
/>
<button onClick={(e) => this.handleEdit(e,index)}>Edit</button>
<button onClick={() => this.handleRemove(index)}>Remove</button>
<button onClick={(e) =>this.handleCancel(e,index)}>Cancel</button>
</div>
);
})}
<button onClick={(e) => this.add(e)}> Add</button>
</div>
);
}
}
export default App;

Reset State on Props Change

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>

Enzyme: Value returns undefined when simulating onSubmit

I'm trying to simulate the way the form was submitted. So to summarize when the user types in the textarea 'field, the component must be updated, then the user presses the submit button and the component is updated again. I expect that the value filled in the textarea will be empty after the user successfully submit. But unexpectedly the returned value is undefined.
CommentBox.js
import React from 'react';
class CommentBox extends React.Component {
state = {
comment: ''
}
handleChange = event => {
this.setState({
comment: event.target.value
})
}
handleSubmit = event => {
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<h4>Add a comment</h4>
<textarea onChange={this.handleChange} value={this.state.comment} />
<div>
<button>Submit Comment</button>
</div>
</form>
)
}
}
export default CommentBox;
CommentBox.text.js
import React from 'react';
import { mount } from 'enzyme';
import CommentBox from 'components/CommentBox';
let wrapped;
beforeEach(() => {
wrapped = mount(<CommentBox />);
})
afterEach(() => {
wrapped.unmount();
})
it('when form is submitted, text area gets emptied', () => {
wrapped.find('textarea').simulate('change', {
target: { value: 'new comment' }
})
wrapped.update();
wrapped.find('form').simulate('submit', {
preventDefault: () => {}
});
wrapped.update();
expect(wrapped.find('textarea').prop('value')).toEqual('');
})
I expect the output will be passed but the actual output is value returns undefined so test is failed.
I don't see anything that would make the test fail... other than not including this.setState({ comment: "" }); in the handleSubmit callback.
If you utilize state, then you have to manually reset it (or if the component unmounts, then it loses state automatically). React works by manipulating a virtual DOM. Then, you utilize state to manipulate the elements within this virtual DOM. Since you're preventing a page refresh (e.preventDefault) the state persists as intended.
Working example (click the Tests tab -- next to the Browser tab -- to run the test):
components/CommentBox
import React, { Component } from "react";
class CommentBox extends Component {
state = { comment: "" };
handleChange = ({ target: { value } }) => {
this.setState({ comment: value });
};
handleSubmit = e => {
e.preventDefault();
console.log("submitted comment: ", this.state.comment);
this.setState({ comment: "" });
};
render = () => (
<div className="app">
<form onSubmit={this.handleSubmit}>
<h4>Add a comment</h4>
<textarea
className="uk-textarea"
onChange={this.handleChange}
value={this.state.comment}
/>
<div className="button-container">
<button type="submit" className="uk-button uk-button-primary">
Submit Comment
</button>
</div>
</form>
</div>
);
}
export default CommentBox;
components/CommentBox/__tests__/CommentBox.test.js
import React from "react";
import { mount } from "enzyme";
import CommentBox from "../index";
describe("Comment Box", () => {
let wrapper;
beforeEach(() => {
wrapper = mount(<CommentBox />);
});
afterEach(() => {
wrapper.unmount();
});
it("when form is submitted, text area gets emptied", () => {
wrapper.find("textarea").simulate("change", {
target: { value: "new comment" }
});
expect(wrapper.find("textarea").prop("value")).toEqual("new comment");
wrapper.find("form").simulate("submit", {
preventDefault: () => {}
});
expect(wrapper.find("textarea").prop("value")).toEqual("");
});
});
handleChange = (e) => {
if(e.keyCode == 13 && e.shiftKey == false) {
e.preventDefault();
this.myFormRef.submit();
}
}
render() {
return (
<form ref={el => this.myFormRef = el} >
<h4>Add a comment</h4>
<textarea onKeyDown={this.handleChange} value={this.state.comment}
/>
<div>
<button type="submit">Submit Comment</button>
</div>
</form>
);
}
you can do like this on enter
You may try this:
import React from 'react';
class CommentBox extends React.Component {
//adding initVal for setting initial value in textbox
// and playing with it until the form submits
state = {
comment: '',
initVal: ''
}
handleChange = event => {
//on change in textfield, updating initVal with the typed text
this.setState({
initVal: event.target.value
})
}
handleSubmit = event => {
//finally on submission comment is updated with entered value
//which you may use it for further operations
//and initVal is set back to empty '' for setting textfield value as empty
//field
this.setState({
comment: this.state.initVal
initVal: ''
})
//event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<h4>Add a comment</h4>
//changes here
<textarea onChange={this.handleChange} value={this.state.initVal} />
<div>
<button>Submit Comment</button>
</div>
</form>
)
}
}
export default CommentBox;

Deleting item on to do list

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!!

Resources