react Todo list "remove" function - javascript

i have tried to remove todo task from my state array but its not working for me. i am having hard time using deletHandle function in Todolist.js. how can i use key from state to indentify and delete clicked(or perticular) todo task
App.js
import React from 'react';
import { Form } from './components/todo-Form/Form.component';
import { Todolist } from './components/Todolist/Todolist.component';
import './App.css';
class App extends React.Component {
constructor() {
super();
this.state = {
todo: [],
do: ""
}
}
render() {
const handleChange = e => {
this.setState({ do: e.target.value }/*, () => { console.log(e) }*/);
};
const submitHandler = e => {
e.preventDefault();
if (this.state.do != "" ) {
this.setState({ todo: [...this.state.todo, { task: this.state.do, id: Math.random() * 1000 }], do: "" }/*, () => { console.log(this.state.todo) }*/)
}
}
const deletHandler = key => {
this.setState({
todo: this.state.todo.filter(el => el !== key)
})
}
return (
<div className="App">
<header>
<h1>ToDo List</h1>
</header>
<Form handleChange={handleChange} submitHandler={submitHandler} inputText={this.state.do} />
<Todolist check={this.state.todo} deletHandler={deletHandler}/>
</div>
)
}
}
export default App;
Todolist.js
import React from "react";
import { Todo } from "../Todo/Todo.component";
import "./todolist.style.css"
export const Todolist = ({check, deletHandler}) => {
return <div >
<ul className="todo-list">
{check.map(todo => (<Todo task={todo.task} key={todo.id} onClick={() => {deletHandler(todo.id)}}/>))}
</ul>
</div>;
};
Todo.js
import React from "react";
import "./todo.style.css";
export const Todo = ({task}) =>{
return (
<div className="todo-container" >
<li className="todo">
<h2> {task} </h2>
<ul className="delet-x">X</ul>
</li>
</div>)
}

In your delete handler, you have to use the id to delete
const deletHandler = (key) => {
this.setState({
todo: this.state.todo.filter((el) => el.id !== key),
});
};

Related

Different class component and func component in handle event react

Can anyone help me explain it, because when use functional it work, but not when use class component
Different class component and func component in handle event react.
fyi it take input text search on child and at parent doing handle event and other
child use functional
import React from "react";
const Header = ({searchTitle,onSearch}) => {
return (
<div>
<header>
<h1>Notes</h1>
<div className="search">
<input
type="text"
placeholder="Search..."
value={searchTitle}
onChange={onSearch}
></input>
</div>
</header>
</div>
);
};
export default Header;
child use class component
import React, { Component } from "react";
export class HeaderPage extends Component {
render() {
const searchTitle = this.props.searchTitle;
const onSearch = this.props.onSearchHandler;
return (
<header>
<h1>Notes</h1>
<div className="search">
<input
type="text"
placeholder="Search..."
value={searchTitle}
onChange={onSearch}
></input>
</div>
</header>
);
}
}
export default HeaderPage;
parent class componet
import React, { Component } from "react";
import HeaderPage from "../organisms/HeaderPage";
import MainPage from "../organisms/MainPage";
import FooterPage from "../organisms/FooterPage";
import { getInitialData } from "../../utils/data";
import Header from "../organisms/Header";
export class PageNote extends Component {
constructor(props) {
super(props);
this.state = {
dataNotes: getInitialData(),
dataNotesFiltered: [],
searchTitle: "",
};
//binding
this.onAddNoteHandler = this.onAddNoteHandler.bind(this);
this.onDeleteHandler = this.onDeleteHandler.bind(this);
this.onArchivedHandler = this.onArchivedHandler.bind(this);
this.onSearchHandler = this.onSearchHandler.bind(this);
}
onAddNoteHandler({ title, body }) {
this.setState((prevState) => {
return {
dataNotes: [
...prevState.dataNotes,
{
id: +new Date(),
title,
body,
archived: false,
createdAt: new Date().toLocaleDateString(),
},
],
};
});
}
onDeleteHandler(id) {
const dataNotes = this.state.dataNotes.filter(
(dataNote) => dataNote.id !== id
);
this.setState({ dataNotes });
}
onArchivedHandler(id) {
const dataNotes = this.state.dataNotes.map((note) => {
if (note.id === id) {
return { ...note, archived: !note.archived };
} else {
return note;
}
});
this.setState({ dataNotes });
}
onSearchHandler(event) {
this.setState(() => {
return {
searchTitle: event.target.value,
};
});
}
render() {
console.log(this.state.dataNotes);
console.log(`search ${this.state.searchTitle}`);
const dataNotes = this.state.dataNotes.filter((note) =>
note.title.toLowerCase().includes(this.state.searchTitle.toLowerCase())
);
return (
<>
<HeaderPage
searchTitle={this.state.searchTitle}
onSearch={this.onSearchHandler}
></HeaderPage>
<Header
searchTitle={this.state.searchTitle}
onSearch={this.onSearchHandler}
></Header>
<MainPage
dataNotes={dataNotes}
addNote={this.onAddNoteHandler}
onDelete={this.onDeleteHandler}
onArchive={this.onArchivedHandler}
></MainPage>
<FooterPage></FooterPage>
</>
);
}
}
export default PageNote;

Getting information about outcome of the class React

I am making project, where you get books cards using Google Books API. I need to count amount of books I get in the end and print in in Header.js(after search). I think I need to add new parameter like 'count' in constructor that will get books.length but still don't know how to pass it in the end.
Books.js
import React, { Component } from 'react';
import SearchArea from './SearchArea';
import request from 'superagent';
import BookList from './BookList';
class Books extends Component {
constructor(props){
super(props);
this.state = {
books: [],
searchField: '',
sort: ''
}
}
searchBook = (e) => {
e.preventDefault();
request
.get("https://www.googleapis.com/books/v1/volumes")
.query({ q: this.state.searchField })
.then((data) => {
console.log(data);
const cleanData = this.cleanData(data)
this.setState({ books: cleanData })
})
}
handleSearch = (e) => {
this.setState ({ searchField: e.target.value })
}
handleSort = (e) => {
console.log(e.target.value)
this.setState({sort: e.target.value})
}
cleanData = (data) => {
const cleanedData = data.body.items.map((book) => {
if(book.volumeInfo.hasOwnProperty('publishedDate') === false){
book.volumeInfo['publishedDate'] = '0000';
}
else if(book.volumeInfo.hasOwnProperty('imageLinks') === false) {
book.volumeInfo['imageLinks'] = {thumbnail: 'https://vignette.wikia.nocookie.net/pandorahearts/images/a/ad/Not_available.jpg/revision/latest?cb=20141028171337'}
}
console.log(this.state.books.length)
return book;
})
return cleanedData;
}
render(){
const sortedBooks = this.state.books.sort((a,b) => {
if(this.state.sort === 'Newest') {
return parseInt(b.volumeInfo.publishedDate.substring(0,4)) - parseInt(a.volumeInfo.publishedDate)
}
else if(this.state.sort === 'Oldest') {
return parseInt(a.volumeInfo.publishedDate.substring(0,4)) - parseInt(b.volumeInfo.publishedDate)
}
})
return (
<div>
<SearchArea searchBook = {this.searchBook} handleSearch={this.handleSearch} handleSort={this.handleSort}/>
<BookList books={this.state.books} />
</div>
);
}
}
export default Books;
SearchArea.js
import React from 'react'
const SearchArea = (props) => {
return(
<div className="search-area">
<form onSubmit={props.searchBook} action="">
<input onChange={props.handleSearch} type="text"/>
<button id="search" type="submit">Search</button>
<select defaultValue="Sort" onChange={props.handleSort}>
bled v<option disaalue="Sort">Sort</option>
<option value="Newest">Newest</option>
<option value="Oldest">Oldest</option>
</select>
</form>
</div>
)
}
export default SearchArea;
BookList.js
import React from 'react';
import BookCard from './BookCard';
const BookList = (props) => {
return(
<div className="list">
{
props.books.map((book,i) => {
return <BookCard
key={i}
image={book.volumeInfo.imageLinks.thumbnail}
title={book.volumeInfo.title}
author={book.volumeInfo.authors}
published={book.volumeInfo.publishedDate}
/>
})
}
</div>
)
}
export default BookList;
Header.js
import React from 'react';
const Header = () => {
return(
<header>
<h1>Book Cards</h1>
</header>
)
}
export default Header;

Why is my DeleteTodos function behaving so oddly in my TodoList App?

I am trying to build a simple todolist app on react and I came up this problem. I could write the code necessary for adding todo items to the list defined in the state and displaying it but when it comes to deleting items off of the list from the click of the button adjacent to every todoitem, all todoitems get removed from the list except the first item. what should I do. Here's the code :
The TodoList(parent) Component:
import React, {Component} from 'react';
import AddTodos from './AddTodos';
import DisplayTodos from './DisplayTodos'
import "./TodoList.css";
class TodoList extends Component {
constructor(props){
super(props);
this.state = {
myList: [],
searchField: ''
}
this.DeleteTodos = this.DeleteTodos.bind(this)
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value})
}
addTodo = () => {
if(this.state.searchField !=="") {
var newItem = {
text: this.state.searchField,
key: Date.now()
}
this.setState({myList: this.state.myList.concat(newItem)})
this.setState({searchField: ""})
console.log(this.state.myList)
} else{
alert("Please enter something")
}
}
DisplayList = () => {
const ListItems = this.state.myList.map((listitem, i) => {
return(
<li key={listitem.key} onClick={(i) => this.DeleteTodos(i)}>{listitem.text} <button>Delete</button>
</li>
)
})
return ListItems;
}
DeleteTodos = (i) => {
i.preventDefault()
this.setState({myList: this.state.myList.splice(i, 1)})
}
render() {
return(
<div className="TodoList">
<AddTodos addTodo={this.addTodo} onSearchChange={this.onSearchChange}/>
<DisplayTodos DisplayList={this.DisplayList}/>
</div>
)
}
}
export default TodoList;
The DisplayTodos Component:
import React, {Component} from 'react';
import AddTodos from './AddTodos';
import DisplayTodos from './DisplayTodos'
import "./TodoList.css";
class TodoList extends Component {
constructor(props){
super(props);
this.state = {
myList: [],
searchField: ''
}
this.DeleteTodos = this.DeleteTodos.bind(this)
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value})
}
addTodo = () => {
if(this.state.searchField !=="") {
var newItem = {
text: this.state.searchField,
key: Date.now()
}
this.setState({myList: this.state.myList.concat(newItem)})
this.setState({searchField: ""})
console.log(this.state.myList)
} else{
alert("Please enter something")
}
}
DisplayList = () => {
const ListItems = this.state.myList.map((listitem, i) => {
return(
<li key={listitem.key} onClick={(i) => this.DeleteTodos(i)}>{listitem.text} <button>Delete</button>
</li>
)
})
return ListItems;
}
DeleteTodos = (i) => {
i.preventDefault()
this.setState({myList: this.state.myList.splice(i, 1)})
}
render() {
return(
<div className="TodoList">
<AddTodos addTodo={this.addTodo} onSearchChange={this.onSearchChange}/>
<DisplayTodos DisplayList={this.DisplayList}/>
</div>
)
}
}
export default TodoList;
AddTodos Component
import React, {Component} from 'react';
import AddTodos from './AddTodos';
import DisplayTodos from './DisplayTodos'
import "./TodoList.css";
class TodoList extends Component {
constructor(props){
super(props);
this.state = {
myList: [],
searchField: ''
}
this.DeleteTodos = this.DeleteTodos.bind(this)
}
onSearchChange = (event) => {
this.setState({searchField: event.target.value})
}
addTodo = () => {
if(this.state.searchField !=="") {
var newItem = {
text: this.state.searchField,
key: Date.now()
}
this.setState({myList: this.state.myList.concat(newItem)})
this.setState({searchField: ""})
console.log(this.state.myList)
} else{
alert("Please enter something")
}
}
DisplayList = () => {
const ListItems = this.state.myList.map((listitem, i) => {
return(
<li key={listitem.key} onClick={(i) => this.DeleteTodos(i)}>{listitem.text} <button>Delete</button>
</li>
)
})
return ListItems;
}
DeleteTodos = (i) => {
i.preventDefault()
this.setState({myList: this.state.myList.splice(i, 1)})
}
render() {
return(
<div className="TodoList">
<AddTodos addTodo={this.addTodo} onSearchChange={this.onSearchChange}/>
<DisplayTodos DisplayList={this.DisplayList}/>
</div>
)
}
}
export default TodoList;
DeleteTodos = (i) => {
i.preventDefault();
let arr = [].concat(this.state.myList);
arr.splice(i, 1);
this.setState({myList: arr});
}
The splice function will change the array and return a new array of deleted items, so you should declair a variable to copy myList, and change the variable. What you do will change the state.

Why react does not trigger component update?

I have custom list with custom methods. Trying to change list and call setState does not trigger component update
import React, {useState} from "react";
class MyCustomArray extends Array {
push(item) {
super.push(item);
return this;
}
}
export default () => {
const [items, setItems] = useState(new MyCustomArray());
console.log(items)
return (
<div>
{items.length}
<button onClick={() => setItems(items.push(1))}/>
</div>
);
}
I have tried same method using class component instead of function and it works.
import React, {Component} from "react";
class MyCustomArray extends Array {
push(item) {
super.push(item);
return this;
}
}
export default class App extends Component {
constructor(props) {
super(props);
this.state = {items: new MyCustomArray()};
}
render() {
const {items} = this.state;
return (
<div>
{items.length}
<button onClick={() => this.setState({items: items.push(1)})}/>
</div>
);
}
}
You need a new instance of items array, use the spread syntax,
import React, { useState } from "react";
class MyCustomArray extends Array {
push(item) {
super.push(item);
return this;
}
}
export default () => {
const [items, setItems] = useState(new MyCustomArray());
return (
<div>
{items.length}
<button onClick={() => setItems([...items, 1])} />
// ^^^^^^^^^^^^^
</div>
);
};
Same thing if you want to use a class Component :
export default class App extends Component {
constructor(props) {
super(props);
this.state = { items: new MyCustomArray() };
}
updateItems = (item) => {
this.setState(prevState => ({
...prevState,
items: [...prevState.items, item]
}));
}
render() {
const { items } = this.state;
return (
<div>
{items.length}
<button onClick={() => this.updateItems(1)} />
</div>
);
}
}

How to render the elements before to filter elements with ReactJS?

I'm doing a project which does a get of the json-server, and render them on the screen.
But when I added a filtering function on it, it only renders after I type a name to filter. I wanted him to render everyone and make the filter.
My Body.js (Where is my function of render):
import React from 'react';
import './Body.css';
import { Link } from "react-router-dom";
class Body extends React.Component {
constructor(props) {
super(props);
this.state = {
input: "",
employeeBody: this.props.employee,
}
}
getName = () => {
const { employee, add } = this.props;
const {employeeBody} = this.state;
return employee.map(name => (
<div className='item'>
<Link className="link" to={`/user/${name.id}`}>
<div onClick={() => add(name)} key={name.id}>
<img className="img"
src={`https://picsum.photos/${name.id}`}
/>
</div>
<h1 className="name2"> {name.name} </h1>
</Link>
</div>
));
};
---
getValueInput = (evt) => {
const inputValue = evt.target.value;
this.setState({ input: inputValue });
this.filterNames(inputValue);
console.log(this.state.employeeBody)
}
filterNames (inputValue) {
const { employee } = this.props;
this.setState({
employeeBody: employee.filter(item =>
item.name.includes(inputValue))
});
}
---
render() {
return (
<div>
<div className="body">
{this.getName()}
</div>
<div className='input'>
<input type="text" onChange={this.getValueInput} />
</div>
</div>
)
}
}
export default Body;
My App.js (Where i get the state by get of axios.):
import React from 'react';
import {
BrowserRouter as Router,
Route
} from "react-router-dom";
import './App.css';
import axios from 'axios';
import Body from './Body';
import User from './User';
import Header from './Header';
class AppRouter extends React.Component {
state = {
employeeCurrent: [],
employee: []
};
componentDidMount() {
axios
.get("http://127.0.0.1:3004/employee")
.then(response => this.setState({
employee: response.data
}));
}
add = name => {
this.setState(prevState => {
const copy = prevState.employeeCurrent.slice(1);
copy.push(name);
return {
employeeCurrent: copy
};
});
};
render() {
return ( <
Router >
<
div className = "router" >
<
Header / >
<
Route exact path = "/"
render = {
props => ( <
Body { ...props
}
add = {
this.add
}
employee = {
this.state.employee
}
employeeCurrent = {
this.state.employeeCurrent
}
/>
)
}
/> <
Route path = "/user/:id"
component = {
props => ( <
User { ...props
}
employee = {
this.state.employee
}
employeeCurrent = {
this.state.employeeCurrent
}
/>
)
}
/> <
/div> <
/Router>
);
}
}
export default AppRouter;
Someone would can help me ?
You should filter in the render method.
render() {
const { employee: employees } = this.props; // rename the variable {employee} to plural {employees}, it has more sense.
const { input } = this.state;
return (
<div>
<div className="body">
{employees
.filter(employee => employee.name.includes(input))
.map(employee => {
<div className='item'>
<Link className="link" to={`/user/${employee.id}`}>
<div onClick={() => add(employee)} key={employee.id}>
<img className="img"
src={`https://picsum.photos/${employee.id}`}
/>
</div>
<h1 className="name2"> {employee.name} </h1>
</Link>
</div>
})}
</div>
<div className='input'>
<input type="text" onChange={(e) => this.setState({ input: e.target.value })} />
</div>
</div>
);
}
Remember that the method includes is case sensitive, it should be lowerCase it before to compare.
P.S.: You could also create a variable / component / function and render split all the "logic" of rendering there.

Categories