Thanks for the help in advance. Currently, I am learning react. As a part of it I am coding a project with a basic listing and deleting the currently clicked listed item. I was able to list the entered item but was not able to delete it. I was able to fetch the id of the currently clicked item but doesn't have a picture of what to do next.Can anyone please help me to solve this.
My code:
App.js
import React, { useState, Fragment } from "react";
import UserAddForm from "./UserAddForm/UserAddForm";
import UserList from "./UserList/UserList";
const App = () => {
const [dataList, setDataList] = useState([]);
const FormDatas = (datas) => {
setDataList([datas, ...dataList]);
};
const deleteListItem = (clickedListId) => {
console.log(clickedListId);
};
return (
<Fragment>
<UserAddForm enteredFormVals={FormDatas} />
<UserList listDatas={dataList} deleteItem={deleteListItem} />
</Fragment>
);
};
export default App;
UserList.js
import React from "react";
import userListing from "./UserList.module.css";
const UserList = (props) => {
const deleteHandler = (e) => {
console.log(e.target.id);
props.deleteItem(e.target.id);
};
return (
<div className={`${userListing.users} ${userListing.whiteBg}`}>
<ul>
{props.listDatas.map((data) => (
<li key={data.id} id={data.id} onClick={deleteHandler}>
{data.name}
{data.age}
</li>
))}
</ul>
</div>
);
};
export default UserList;
UserAddForm.js
import React, { useState } from "react";
import UserForm from "./UserAddForm.module.css";
const UserAddForm = (props) => {
const [enteredName, setEnteredName] = useState("");
const [enteredAge, setEnteredAge] = useState("");
const nameHandler = (e) => {
setEnteredName(e.target.value);
};
const ageHandler = (e) => {
setEnteredAge(e.target.value);
};
const userFormHandler = (e) => {
e.preventDefault();
const EnteredFormDatas = {
name: enteredName,
age: enteredAge,
id: Math.random().toString(),
};
props.enteredFormVals(EnteredFormDatas);
};
return (
<div className={`${UserForm.input} ${UserForm.whiteBg}`}>
<form onSubmit={userFormHandler}>
<label htmlFor="username">Username</label>
<input
id="username"
type="text"
onChange={nameHandler}
value={enteredName}
/>
<label htmlFor="age">Age (Years)</label>
<input
id="age"
type="number"
onChange={ageHandler}
value={enteredAge}
/>
<button type="submit" className={UserForm.button}>
Add User
</button>
</form>
</div>
);
};
export default UserAddForm;
You need to filter out the item from the array by keeping ones with a different id and set it back as a new dataList.
const deleteListItem = (clickedListId) => {
setDataList(items => items.filter(({ id }) => id !== clickedListId))
};
Related
I am creating a blog website in which I am embedding react-draft-wysiwyg editor. I am facing problem when the user has to update the blog. When I click the update button the content is gone. I looked into many solutions but I couldn't make it work.
This is my code
import axios from "axios";
import React, { useContext, useEffect, useState } from "react";
import { useLocation } from "react-router";
import { Link } from "react-router-dom";
import { Context } from "../../context/Context";
import "./singlePost.css";
import { EditorState, ContentState, convertFromHTML } from 'draft-js';
import { Editor } from 'react-draft-wysiwyg';
import { convertToHTML } from 'draft-convert';
import DOMPurify from 'dompurify';
import 'react-draft-wysiwyg/dist/react-draft-wysiwyg.css';
import Parser from 'html-react-parser';
export default function SinglePost() {
const location = useLocation();
const path = location.pathname.split("/")[2];
const [post, setPost] = useState({});
const PF = "http://localhost:5000/images/";
const { user } = useContext(Context);
const [title, setTitle] = useState("");
const [desc, setDesc] = useState("");
const [updateMode, setUpdateMode] = useState(false);
useEffect(() => {
const getPost = async () => {
const res = await axios.get("/posts/" + path);
setPost(res.data);
setTitle(res.data.title);
setDesc(res.data.desc);
};
getPost();
}, [path]);
const handleDelete = async () => {
try {
await axios.delete(`/posts/${post._id}`, {
data: { username: user.username },
});
window.location.replace("/");
} catch (err) {}
};
// updating post
const handleUpdate = async () => {
try {
await axios.put(`/posts/${post._id}`, {
username: user.username,
title,
desc,
});
setUpdateMode(false)
} catch (err) {}
};
const [editorState, setEditorState] = useState(
() => EditorState.createWithContent(
ContentState.createFromBlockArray(
convertFromHTML(desc)
)
),
);
const [convertedContent, setConvertedContent] = useState(null);
const handleEditorChange = (state) => {
setEditorState(state);
convertContentToHTML();
}
const convertContentToHTML = () => {
let currentContentAsHTML = convertToHTML(editorState.getCurrentContent());
setConvertedContent(currentContentAsHTML);
setDesc(currentContentAsHTML);
}
const createMarkup = (html) => {
return {
__html: DOMPurify.sanitize(html)
}
}
return (
<div className="singlePost">
<div className="singlePostWrapper">
{post.photo && (
<img src={PF + post.photo} alt="" className="singlePostImg" />
)}
{updateMode ? (
<input
type="text"
value={title}
className="singlePostTitleInput"
autoFocus
onChange={(e) => setTitle(e.target.value)}
/>
) : (
<h1 className="singlePostTitle">
{title}
{post.username === user?.username && (
<div className="singlePostEdit">
<i
className="singlePostIcon far fa-edit"
onClick={() => setUpdateMode(true)}
></i>
<i
className="singlePostIcon far fa-trash-alt"
onClick={handleDelete}
></i>
</div>
)}
</h1>
)}
<div className="singlePostInfo">
<span className="singlePostAuthor">
Author:
<Link to={`/?user=${post.username}`} className="link">
<b> {post.username}</b>
</Link>
</span>
<span className="singlePostDate">
{new Date(post.createdAt).toDateString()}
</span>
</div>
{updateMode ? (
// <textarea
// className="singlePostDescInput"
// value={desc}
// onChange={(e) => setDesc(e.target.value)}
// />
<Editor
contentState={desc}
editorState={editorState}
onEditorStateChange={handleEditorChange}
wrapperClassName="wrapper-class"
editorClassName="editor-class"
toolbarClassName="toolbar-class"
/>
) : (
<p className="singlePostDesc">{Parser(desc)}</p>
)}
{updateMode && (
<button className="singlePostButton" onClick={handleUpdate}>
Update
</button>
)}
</div>
</div>
);
}
I want to display desc which is saved in MongoDB database when the user clicks on update button.
The following part is what I tried to do but didn't work.
const [editorState, setEditorState] = useState(
() => EditorState.createWithContent(
ContentState.createFromBlockArray(
convertFromHTML(desc)
)
),
);
I am getting warning in this:
react.development.js:220 Warning: Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the r component.
Please help
Please help with the task. I have 2 components: Header, which has a Modal component (for a modal window) and a Main_Part component. I don't know how to make so that on the Create button values from input were created in the Main_part component.
How can this be done? Thanks
Main_part.js
import React from "react";
import "./Main_Part.css";
export let Main_Part = ({newList}) => {
return (<div className="main">
</div>)
}
Header.js
import React, {useState} from "react";
import "./Header.css";
import {Modal} from "../Modal/Modal";
import {Main_Part} from "../Main_Part/Main_Part";
export let Header = () => {
let [modalActive, setModalActive] = useState(false);
let [newList, setNewList] = useState([]);
let [input, setInput] = useState('');
let addList = (myInput) => {
let newDiscussion = {
id: Math.random(),
task: myInput
}
setNewList([...newList, newDiscussion])
}
let handleInput = (e) => {
setInput(e.target.value)
}
let submitTask = (e) => {
e.preventDefault();
addList(input);
setInput('')
}
return (<header className="header">
<div>
<button onClick={() => setModalActive(true)}>Створити новий список</button>
</div>
<Modal active={modalActive} setActive={setModalActive}>
<form onSubmit={submitTask}>
<input
type="text"
placeholder="Створити"
onChange={handleInput}
/>
<button type="submit" onSubmit={submitTask}>Create</button>
</form>
<button onClick={() => setModalActive(false)}>Закрити</button>
</Modal>
<Main_Part newList={newList}/>
</header>)
}
Here's the simple sample of what you're wanting to do. You just need to pass the input values to Main_Part and check its for not null definition in Main_Part:
newList && newList.map((v, i) => v.task)
Here's the example:
import { useState } from "react";
import "./styles.css";
const Main_Part = ({ newList }) => {
return <div className="main">{newList && newList.map((v, i) => v.task)}</div>;
};
const Header = () => {
let [modalActive, setModalActive] = useState(false);
let [newList, setNewList] = useState([]);
let [input, setInput] = useState("");
let addList = (myInput) => {
let newDiscussion = {
id: Math.random(),
task: myInput
};
setNewList([...newList, newDiscussion]);
};
let handleInput = (e) => {
setInput(e.target.value);
};
let submitTask = (e) => {
e.preventDefault();
addList(input);
setInput("");
};
return (
<header className="header">
<form onSubmit={submitTask}>
<input type="text" placeholder="Створити" onChange={handleInput} />
<button type="submit" onSubmit={submitTask}>
Create
</button>
</form>
<button onClick={() => setModalActive(false)}>Закрити</button>
<Main_Part newList={newList} />
</header>
);
};
export default function App() {
return (
<>
<Header />
<Main_Part />
</>
);
}
I have json data file. I want to make a search with the names of the data and display the typed names when I click the search button.
I get the value of input in the console when I type something however I am not able to display it on the screen
How can I display the value of this input ?
my code is below
PostResults.jsx
import React from "react";
const PostResults = (props) => {
const {name} = props.posts
return(
<div className="">
<p className="titles">{name}</p>
</div>
)
}
export default PostResults
Posts.jsx
import React, { useState, useEffect } from "react";
import PostResults from './PostResults'
const Posts = (props) => {
const [posts, setPosts] = useState([]);
const [searchTerm,setSearchTerm]=useState([]);
const getData = () => {
fetch('data.json')
.then(response => {
return response.json()
//console.log(response)
})
.then(data => {
setPosts(data)
console.log(data)
})
}
useEffect(() => {
getData()
},[])
const submitHandler = (event) => {
event.preventDefault()
{searchTerm ? searchTerm : console.log("none")}
}
return(
<div className="">
<input
type="text"
placeholder="Search Anything"
name="query"
onChange={e => setSearchTerm(e.target.value)}
className="search-input"
/>
<button
onClick={submitHandler}
type="submit"
className="search-button"
>
<i className="fas fa-search"></i>
</button>
{posts.map(posts => (
<PostResults key={posts.id} posts={posts}/>
))}
</div>
)
}
export default Posts
App.jsx
import React from "react";
import "./style.css";
import 'bootstrap/dist/css/bootstrap.min.css'
import Posts from './components/Posts'
export default function App() {
return (
<div className="container">
<div className="row">
< Posts />
</div>
</div>
);
}
I am trying to write the very first to-do application in REACT. I want to add functionality to delete to-do item when the user clicks on the delete icon. When I click on delete icon it only removes the text. Here I would like to delete the entire item. Can someone please suggest?
App.js
import './App.css';
import { useState } from 'react';
import TodoList from './TodoList';
import { v4 as uuidv4 } from 'uuid';
function App() {
const [input, setInput] = useState('');
const [todos, setTodo] = useState([]);
const addTodo = (e) => {
e.preventDefault();
const id = uuidv4();
setTodo([...todos, { id: id, text: input}])
// setTodo({todos: [...todos, input], id })
setInput('');
}
const deleteTodo = (id) => {
console.log("id" + id);
const filteredItem = todos.filter(todo => todo.id !== id);
setTodo([filteredItem]);
}
return (
<div className="App">
<form>
<input type="text" value={input} onChange={(e) => setInput(e.target.value)}/>
<button type="submit" onClick={addTodo}>Enter</button>
</form>
<TodoList todos={todos} deletetodo={deleteTodo}/>
</div>
);
}
export default App;
TodoList.js
import React from 'react'
import DeleteIcon from '#material-ui/icons/Delete';
import EditIcon from '#material-ui/icons/Edit';
const todo = ({todos, deletetodo}) => {
return (
<div>
{todos.map(todo => (
<li key={todo.id}>
{todo.text}
<div>
<DeleteIcon onClick={(todo) => deletetodo(todo.id)}/>
<EditIcon/>
</div>
</li>
))}
</div>
)
}
export default todo;
There are a few problems with your code. I will start with the most obvious. You re-render your App on EVERY change of the input field. That's just unnecessary. So insated of storing the value of the input in a state variable, I would use useRef(). So you only really need one state variable, one that stores the list of todos.
Second, your filter is correct, but then you incorrectly set the state variable with the filtered result:
const filteredItem = todos.filter(todo => todo.id !== id);
setTodo([filteredItem]);
It will already return an array and there is no need to wrap it into another one.
With those 2 main issue fixed, here is a working example along with a Sandbox:
import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";
import "./styles.css";
const TodoList = ({ todos, deletetodo }) => {
return (
<div>
{todos.map((todo) => (
<li key={todo.id}>
{todo.text}
<div>
<button onClick={() => deletetodo(todo.id)}>delete</button>
<button>edit</button>
</div>
</li>
))}
</div>
);
};
export default function App() {
const [todos, setTodo] = useState([]);
const input = React.useRef();
const addTodo = (e) => {
e.preventDefault();
const id = uuidv4();
setTodo([...todos, { id: id, text: input.current.value }]);
input.current.value = "";
};
const deleteTodo = (id) => {
setTodo(todos.filter((item) => item.id !== id));
};
return (
<div className="App">
<form>
<input ref={input} type="text" />
<button type="submit" onClick={addTodo}>
Enter
</button>
</form>
<TodoList todos={todos} deletetodo={deleteTodo} />
</div>
);
}
You have a mistake in how you're setting todo in deleteTodo:
const deleteTodo = (id) => {
console.log("id" + id);
const filteredItem = todos.filter(todo => todo.id !== id);
// Mistake! Your filteredItem is an array, you're putting your array into an array.
setTodo([filteredItem]);
}
Consequently, when you pass it further down, your component tries to get [filteredItem].text, which is undefined and React sees an empty string.
Fix:
setTodo(filteredItem);
There are multiple issues within the code:
First one is setting the values after deleting the row:
should be like this : setTodo(filteredItem);
Second issue was calling the onClick function, you already have the id with you so no need to re-call it again:
<div>
{todos.map(todoss =>
<li onClick={() => deletetodo(todoss.id)} key={todoss.id}>
{todoss.text}
</li>
)}
</div>
I have a demo here
Its a simple cart app where I'm listing products and then adding them to a cart components
It uses context for the app state.
I'd now like to be able to remove items from the cart but I'm struggling to get this to work.
Do I need to add a DeleteCartContext.Provider
import React, { useContext } from "react";
import { CartContext } from "./context";
import { IProduct } from "./interface";
const Cart = () => {
const items = useContext(CartContext);
const handleClick = (
e: React.MouseEvent<HTMLInputElement, MouseEvent>,
item: IProduct
) => {
e.preventDefault();
};
const cartItems = items.map((item, index) => (
<div>
<span key={index}>{`${item.name}: £${item.price}`}</span>
<input type="button" value="-" onClick={e => handleClick(e, item)} />
</div>
));
return (
<div>
<h2>Cart</h2>
{cartItems}
</div>
);
};
export default Cart;
There are many ways to control Items in Context so I tried to answer as similar to your structure, here is how you do that:
import React, { useContext } from "react";
import { CartContext, RemoveCartContext } from "./context";
import { IProduct } from "./interface";
const Cart = () => {
const items = useContext(CartContext);
const removeItem = useContext(RemoveCartContext);
const handleClick = (
e: React.MouseEvent<HTMLInputElement, MouseEvent>,
item: IProduct
) => {
e.preventDefault();
};
const cartItems = items.map((item, index) => (
<div>
<span key={index}>{`${item.name}: £${item.price}`}</span>
<input type="button" value="+" onClick={e => handleClick(e, item)} />
<input type="button" value="-" onClick={e => removeItem(item)} />
</div>
));
return (
<div>
<h2>Cart</h2>
{cartItems}
</div>
);
};
export default Cart;
import React, { createContext, useCallback, useRef, useState } from "react";
export const CartContext = createContext([]);
export const AddCartContext = createContext(item => {});
export const RemoveCartContext = createContext(item => {});
export const CartProvider = ({ children }) => {
const [items, setItems] = useState([]);
const itemsRef = useRef(items);
itemsRef.current = items;
return (
<AddCartContext.Provider
value={useCallback(item => {
setItems([...itemsRef.current, item]);
}, [])}
>
<RemoveCartContext.Provider
value={useCallback(item => {
const newItems = itemsRef.current.filter(
_item => _item.id !== item.id
);
setItems(newItems);
}, [])}
>
<CartContext.Provider value={items}>{children}</CartContext.Provider>
</RemoveCartContext.Provider>
</AddCartContext.Provider>
);
};
and here is a working demo: https://stackblitz.com/edit/react-ts-cart-context-mt-ytfwfv?file=context.tsx