Change the value in massive by pressing button(React) - javascript

Ok, so I am creating employers list with salary and Names. I want to change color of text by changing value of variable - "increase" from false to true for example. I already created code to change text taking value FROM variable
<li className={ increase ? "list-group-item d-flex justify-content-between increase" : "list-group-item d-flex justify-content-between"}>
Now I need to change value of "increase" by clicking a button <i className="fas fa-cookie"></i>
Here is a full code:
const EmployeesListItem = ({name, salary, increase}) => {
return (
//-------Here I check the value of variable----->
<li className={ increase ? "list-group-item d-flex justify-content-between increase" : "list-group-item d-flex justify-content-between"}>
<span className="list-group-item-label">{name}</span>
<input type="text" className="list-group-item-input" defaultValue={salary + "$"}/>
<div className='d-flex justify-content-center align-items-center'>
<button type="button"
className="btn-cookie btn-sm ">
<i className="fas fa-cookie"></i> //by clicking in this button I wanna change value of increase variable
</button>
<button type="button"
className="btn-trash btn-sm ">
<i className="fas fa-trash"></i>
</button>
<i className="fas fa-star"></i>
</div>
</li>
)
}
export default EmployeesListItem;
Here is EmployerList structure:
import EmployeesListItem from '../employeers-list-item/employeers-list-item'
import './employers-list.css'
const EmployersList = ({data}) => {
const elements = data.map(item => {
return(
<EmployeesListItem {...item} data={data}/> //name={item.name} salary={item.salary}
)
})
return (
<ul className='app-list list-group'>
{elements}
</ul>
)
}
export default EmployersList;
And here is App component:
function App() {
const data = [
{name: 'killer228brawlstarsassasin1993', salary:2300 ,increase: true},
{name: 'jotaro', salary:800 ,increase: false},
{name: 'Ktoh', salary:300 ,increase: true}
]
return (
<div className="app">
<AppInfo/>
<div className="search-panel">
<SearchPanel>
</SearchPanel>
<AppFilter/>
</div>
<EmployersList data={data}/>
<EmployeesAddForm/>
</div>
)
}
export default App;
the program works, but still don't know how to change the value of the INCREASE variable in the APP component by clicking on the button

You should read about React Context, this will help you to store data so it is accessible from every component: https://reactjs.org/docs/context.html
The way your app works now you need to pass a "changeIncrease"-function as prop to the EmployeesListItem component.
const changeIncrease = (name) => {
data.forEach(employee, index) => {
if(employee.name == name) {
data[index] = {...emloyee, increase: !employee.increase}
}
}
}
Maybe there's a more elegant solution out there, but this should do it

Related

how do i map an array in react js i have tried but there is some problem can anyone help me

So I try to get data from localDataStorage and try to populate on screen in react but the react is showing error `[{',' expected" in place of '.' in jsx line localStorageData.iength or if i remove this from code than it's showing same error for 'localDataStorage.map' it asking me to remove '.'
import { useEffect, useState } from "react";
import "./inbox.css";
const Inbox = () => {
const [localStorageData, setlocalStorageData] = useState([])
useEffect =(()=>{
JSON.parse(localStorage.getItem('todos')).then(data=> setlocalStorageData(data))
}, [localStorageData])
return (
{localStorageData.length > 0 &&
localDataStorage.map((element, index) => (
<div className="inbox" key ={index}>
<div className="bullet">➣</div>
<div className="msg">{element.message}</div>
<div className="btn-container">
<div className="date">{element.title}</div>
<div className="edit btn hide">
<i className="fa-solid fa-pen-to-square"></i>
</div>
<div className="delete btn hide">
<i className="fa-solid fa-trash"></i>
</div>
</div>
</div>
))
}
)
}
export default Inbox;
the error is as following
[{
"resource": "/C:/Users/PC/Desktop/web/new/src/component/inbox/inbox.js",
"owner": "typescript",
"code": "1005",
"severity": 8,
"message": "',' expected.",
"source": "ts",
"startLineNumber": 14,
"startColumn": 22,
"endLineNumber": 14,
"endColumn": 23
}]
Remove the outer braces in your return statement. Braces like this are only used inside JSX.
Also, you probably meant .length instead of .iength.
import React from "react"
import { useEffect, useState } from "react"
import "./inbox.css"
const Inbox = () => {
const [localStorageData, setlocalStorageData] = useState([])
useEffect =
(() => {
JSON.parse(localStorage.getItem("todos"))
.then(data => setlocalStorageData(data))
.catch(err => console.log(err))
},
[localStorageData])
return (
<>
{localStorageData.length > 0 &&
localStorageData.map((element, index) => (
<div className="inbox" key={index}>
<div className="bullet">➣</div>
<div className="msg">{element.message}</div>
<div className="btn-container">
<div className="date">{element.title}</div>
<div className="edit btn hide">
<i className="fa-solid fa-pen-to-square"></i>
</div>
<div className="delete btn hide">
<i className="fa-solid fa-trash"></i>
</div>
</div>
</div>
))}
</>
)
}
export default Inbox
you are not wrapping code into single element
try
return (
<>
{
localStorageData.length > 0 &&
localData.map((element, index) => (
<div className="inbox" key={index}>
<div className="bullet">➣</div>
<div className="msg">{element.message}</div>
<div className="btn-container">
<div className="date">{element.title}</div>
<div className="edit btn hide">
<i className="fa-solid fa-pen-to-square"></i>
</div>
<div className="delete btn hide">
<i className="fa-solid fa-trash"></i>
</div>
</div>
</div>
))
}
</>
)
i believe there should be localStorageData.map and not localData.map

How can I delete an item from my todolist

I am trying to learn react js , but I don't know how to delete an item from my list, could you help me ? Actually, I am not professional , but I am really interested in learning, there is my codes which add some new item to my list properly, but I don't know how to delete them when I click on their checkbox/delete button.
import React, { useState } from "react";
const App = () => {
const [NewTaskText, setNewTaskText] = useState("");
const [Tasks, setTasks] = useState(["do a task", "samira"]);
const addTask = (e) => {
e.preventDefault();
if (!NewTaskText) return;
setTasks((currentTasks) => {
return [...currentTasks, NewTaskText];
});
setNewTaskText("");
};
const onchangeInput = (e) => {
const value = e.target.value;
setNewTaskText(value);
};
return (
<div className="row">
<form onSubmit={addTask}>
<div className="row col s6">
<div className="input-field col s10">
<textarea
id="textarea1"
className="materialize-textarea"
value={NewTaskText}
onChange={onchangeInput}
></textarea>
<label htmlFor="textarea1">What needs to be done ?</label>
</div>
</div>
<div className="row col s6">
<br></br>
<a className='waves-effect waves-light btn' href="/#" onClick={addTask}>
<i className='material-icons left' >
add_circle
</i>
Add
</a>
</div>
</form>
<div className="row">
<div className="row col s9">
<ul className="collection with-header">
<li className="collection-header">
<h4>Todo List</h4>
<form>
<div className="input-field">
<input id="search" type="search" required />
<label className="label-icon" htmlFor="search">
<i className="material-icons">search</i>Search
</label>
<i className="material-icons">close</i>
</div>
</form>
</li>
<label>
{Tasks.map((item, i) => {
return (
<li className="collection-item" key={i}>
<input type="checkbox" />
<span>
{item}
</span>
<span>
<a href="#!" className="secondary-content">
<i className="material-icons" >delete</i>
<i className="material-icons">check_circle</i>
</a>
</span>
</li>
);
})}
</label>
</ul>
</div>
</div>
</div>
);
};
export default App;
You can delete the item from the array by using index:
<i className="material-icons" onClick={() => handleDelete(i)}>delete</i>
and define your function above the return statement:
const handleDelete = i => {
const taskList = [...Tasks]
taskList.splice(i, 1)
setTasks(taskList)
}
Here it is important to know that you have to make a copy of the state if it is an object or an array. Because if you modify the original array or object, react won't register that as a change, and won't re-render. That is why I did const taskList = [...Tasks]. You can also use a library like lodash which provides some neat ways of handling objects and arrays
Just add a onClick handler to button which should delete item
<i className="material-icons" onClick={ () => {
setTasks((prevTasks) => {
const updatedPrevTasks = [...prevTasks];
updatedPrevTasks.splice(i, 1);
return updatedPrevTasks;
});
}}>delete</i>

React/Redux, Redux store changes but does not immediately render items without leaving the page and returning

When I clicked on the button "Buy", the store redux is updated and
push a new array to the initial state. But I don't see any new render
in the shop-cart section without leaving the page and go in again so I
can see new items. I'm new to React and Redux, I have been trying to fix it but it was not working and i'm very confused about it
Here is the reducer section
const initialState = {
counter : 0,
cartData : [
{
id : 1,
name : "Melon",
price : 100,
img : "https://d1hr6nb56yyl1.cloudfront.net/product-images/93368-280.jpg",
quantity : 1
},
{
id : 1,
name : "Melon",
price : 100,
img : "https://d1hr6nb56yyl1.cloudfront.net/product-images/93368-280.jpg",
quantity : 1
},
]
};
function cartNumber(state = initialState, action) {
console.log(state.cartData)
let cartIndex = [...state.cartData];
switch(action.type){
case "INCREMENT" :
return {
...state,
cartData : cartIndex.concat(action.newData)
};
break;
case "DECREMENT" :
default :
return state;
}
return cartIndex
}
export default cartNumber;
Here is the Item Detail page and Items Cart section
import React, {useEffect,useState} from "react";
import SubCart from "../components/SubCart";
import { useSelector, useDispatch } from "react-redux";
import {Link} from "react-router-dom";
function ItemDetail({match, history}){
const dispatch = useDispatch();
const [item, setItem] = useState({});
const scroll = () => {window.scroll(0,0)};
useEffect(() => {
const fetchItem = async () => {
const fetchItem = await fetch(
`https://5e5a9fc26a71ea0014e61f04.mockapi.io/api/${match.params.category}/${match.params.id}`
);
const item = await fetchItem.json();
setItem(item);
};
fetchItem();
scroll();
}, [])
const showRating = (rating) => {
var result = [];
for(var i = 1; i <= rating; i++){
result.push(<i className="fa fa-star" key={i + 1} style={{fontSize : ".8rem", color : "#ff4e00", padding : "0rem .1rem"}}></i>);
}
for (var j = 1; j <= (5-rating); j++) {
result.push(<i className="far fa-star" key={i + 1} style={{fontSize : ".8rem", padding : "0rem .1rem"}}></i>);
}
return result;
}
const backButton = () => {
history.goBack();
}
const showSubcart = () => {
let sub = document.getElementById("subcart-section");
let bg = document.getElementById("bg-ccc");
sub.classList.toggle("showSubCart");
bg.classList.toggle("bg-ccc");
dispatch({type : "INCREMENT", newData : item });
}
return (
<div style={{backgroundColor: "white"}}>
<div className="item-detail" style={{paddingBottom : "1rem"}}>
<div className="section-heading">
<div className="section-content">
<div className="icon-home">
<i className="fas fa-home"></i>
</div>
<div className="nav-home">
<Link to="/">Home</Link>
</div>
<div className="icon-to">
<i className="fas fa-chevron-right"></i>
</div>
<div className="nav-cart">
<Link to="/">{item.category}</Link>
</div>
</div>
</div>
<div className="img-detail">
<img src={item.img} alt={item.name} />
<span className="icon-section"><i className="far fa-heart"></i></span>
<span className="icon-section-arrow" onClick={() => backButton()}><i className="fas fa-arrow-left"></i></span>
</div>
<div className="item-detail-content">
<div className="container">
<Link to="/" style={{color : "black"}}><span className="category">{item.category}</span></Link>
<div><h2>{item.name}</h2></div>
<div><h3>{item.price}$</h3></div>
<div>
<ul>
<li>{showRating(item.rating)} <span style={{fontSize : ".8rem"}}>(210)</span></li>
</ul>
</div>
<div className="buy" onClick={() => showSubcart()}>
<span className="buy-text">Buy</span>
<span className="buy-icon"><i className="fas fa-shopping-cart"></i></span>
</div>
<div className="description">
<div className="head-description">
<h3><i className="far fa-bookmark"></i> Description</h3>
</div>
<div className="body-description">
<p>...</p>
</div>
</div>
<div className="infoPolicy mt-top">
<div className="box-head">
<i className="fas fa-truck"></i>
</div>
<div className="box-content">
<p className="note-p">FREE NATIONAL DELIVERY</p><span className="note">(Products over 50$)</span>
</div>
</div>
<div className="infoPolicy mt-top">
<div className="box-head">
<i className="fas fa-sync-alt"></i>
</div>
<div className="box-content">
<p className="note-p">Returns are Easy</p><span className="note">(Return 30days for items)</span>
</div>
</div>
<div className="infoPolicy mt-top mt-bt">
<div className="box-head">
<i className="fas fa-headset"></i>
</div>
<div className="box-content">
<p className="note-p">Telephone consultation</p><span className="note">(Free from 8:00 - 21:00 every day)</span>
</div>
</div>
</div>
</div>
<SubCart />
</div>
</div>
);
}
export default ItemDetail;
import React, {useState} from "react";
import {Link} from "react-router-dom";
import {useSelector} from "react-redux";
function ItemCart(){
let data = useSelector(state => state.cartData);
let [items, setItem] = useState(data);
return (
<div className="subcart-link">
{items.map((item, index) => (
<div className="d-flex" key={index}>
<div className="subcart-img">
<img src={item.img} alt="pubg"/>
</div>
<div className="subcart-item-content">
<Link to="/">{item.name}</Link>
<div className="subcart-item-detail">
<p>{item.price}$<span className="subcart-quantity">x 2</span></p>
</div>
</div>
<div className="delete-click">
<p>x</p>
</div>
</div>
))}
</div>
);
}
at your ItemCart you are duplicating redux state into a react state, which is not advisable. they are two different entities, though you can have both types at your application a given specific state should be handled by a specific state manager.
at your ItemCart remove useState altogether, and map over data variable instead. your issue comes from the fact that your items state inherits only the original redux state, but since they are different states, it doesnt get updated when redux state changes.
fwiw, dont use dom manipulation to handle classes like you do at showSubCart, this is not good. I suggest to use some boolean logic instead to toggle class, based on some props or state value.

Adding a selected list entry to a new list entry

How can I move the selected list entry by clicking button and move it to a new list entry
<pre className="reverse-list">
{datas.map((data, i) =>
<li key={i} className="list-group-item text-capitalize d-flex
justify-content-between my-2">
<div className="todo-icon">
<span>
<button></button>
</span>
</div>
<h6 className="mt-2">{data.input}</h6>
<div className="todo-icon">
<span className="mx-2 text-success">
<i className="fas fa-pen" onClick={()=>this.fEdit(i)</i>
</span>
<span className="mx-2 text-danger">
<i className="fas fa-trash" onClick={()=>this.fRemove(i)</i>
</span>
</div>
</li>
)}
</pre>
Methods used
constructor(props){
super(props);
this.state={
title: 'Todo List',
act: 0,
index: '',
datas: []
}
}
componentDidMount(){
this.refs.input.focus();
}
What should i add in the fcomplete method to get the required output?
fSubmit = (e) =>{
e.preventDefault();
console.log('try');
let datas = this.state.datas;
let input = this.refs.input.value;
if(this.state.act === 0){ //new
let data = {
input
}
datas.push(data);
}else{ //update
let index = this.state.index;
datas[index].input = input;
}
this.setState({
datas: datas,
act: 0
});
this.refs.myForm.reset();
this.refs.input.focus();
}
fComplete = (i) => {
}
fRemove = (i) => {
let datas = this.state.datas;
datas.splice(i,1);
this.setState({
datas: datas
});
this.refs.myForm.reset();
this.refs.input.focus();
}
fEdit = (i) => {
let data = this.state.datas[i];
this.refs.input.value = data.input;
this.setState({
act: 1,
index: i
});
this.refs.input.focus();
}
I have tried using methods in fcomplete(). But I was not able to get the task done.I have added the complete code.
csccscsccs
csscscsccssc
If I understand you correctly, you want to display your list in such a way that the items marked as completed are displayed at the bottom of the list. My below answer is based on this assumption only.
Like I mentioned in the comments, you have to store your list in a different way:
fSubmit = (e) =>{
e.preventDefault();
console.log('try');
let datas = this.state.datas;
let input = this.refs.input.value;
if(this.state.act === 0){ //new
let data = {
id: (Math.floor(Math.random() * 100) + 1), // for generating random ids
value: input,
isComplete: false // you have to make this change here while creating the data item
}
datas.push(data);
}else{ //update
let index = this.state.index;
datas[index].input = input;
}
this.setState({
datas: datas,
act: 0
});
this.refs.myForm.reset();
this.refs.input.focus();
}
fComplete = (id) => {
// use id to update the list
// use this in fEdit & fRemove
const updatedDataList = this.state.datas.map(data => {
if(data.id === id) {
data.isComplete = true
}
return data;
});
this.setState({
datas: updatedDataList
});
}
render() {
const incompleteList = datas.filter(data => data.isComplete === false);
const completeList = datas.filter(data => data.isComplete === true);
...
...
...
}
Display the two lists separately. (I don't understand your css classes, that you can see according to your design.) The idea is to display them in two separate lists to make it simple. Or otherwise you have to always modify your "datas" list and keep the incomplete list on top and append the completed data items at the end.
<pre className="reverse-list">
{incompleteList.map((data, i) =>
<li key={i} className="list-group-item text-capitalize d-flex
justify-content-between my-2">
<div className="todo-icon">
<span>
<button onClick={() => this.fComplete({data.id})}></button>
</span>
</div>
<h6 className="mt-2">{data.input}</h6>
<div className="todo-icon">
<span className="mx-2 text-success">
<i className="fas fa-pen" onClick={()=>this.fEdit({data.id})</i>
</span>
<span className="mx-2 text-danger">
<i className="fas fa-trash" onClick={()=>this.fRemove({data.id})</i>
</span>
</div>
</li>
)}
{completeList.map((data, i) =>
<li key={i} className="list-group-item text-capitalize d-flex
justify-content-between my-2">
<div className="todo-icon">
<span>
<button></button>
</span>
</div>
<h6 className="mt-2">{data.input}</h6>
<div className="todo-icon">
<span className="mx-2 text-success">
<i className="fas fa-pen" onClick={()=>this.fEdit(i)</i>
</span>
<span className="mx-2 text-danger">
<i className="fas fa-trash" onClick={()=>this.fRemove(i)</i>
</span>
</div>
</li>
)}
</pre>

How to update upvote counter for individual elements instead of all of them at once with React

Newbie dev learning React.
I'm trying to create an upvote functionality to a blog post in React but when I click on the upvote button I'm upvoting all of the blog post cards at once instead of the individual card.
How can I fix this? I believe the issue may be in the way I'm setting setState? But I may be wrong and looking for help.
Thanks in advance!
====
class Posts extends Component {
state= {
points: 0
}
componentDidMount() {
this.props.fetchPosts()
}
UNSAFE_componentWillReceiveProps(nextProps) {
if (nextProps.newPost) {
this.props.posts.unshift(nextProps.newPost);
}
}
handleClick = () => {
this.setState({points: this.state.points + 1})
}
render() {
const postItems = this.props.posts.map((post, index) => (
<div key={index} className="ui three stackable cards">
<div className="ui card">
<div className="content">
<div className="header">{post.title}</div>
<div className="meta"> {post.author}</div>
<div className="description">
<p>{post.body}</p>
</div>
</div>
<div className="extra content">
<i className="check icon"></i>
{this.state.points} Votes
</div>
<button className="ui button"
type="submit"
onClick={this.handleClick}>Add Point</button>
</div>
</div>
))
return (
<div>
<br />
<h2 className="ui header">
<i className="pencil alternate icon"></i>
<div className="content">
Blog Feed
<div className="sub header">Create New Post!</div>
</div>
</h2>
{postItems}
</div>
)
}
}
You have a single component storing the "points" state for all your posts. To achieve the functionality you described, each post should be it's own component with it's own state.
class Post extends Component {
state = {
points: 0
}
handleClick = () => {
this.setState({points: this.state.points + 1})
}
render = () =>
<div key={index} className="ui three stackable cards">
<div className="ui card">
<div className="content">
<div className="header">{this.props.title}</div>
<div className="meta"> {this.props.author}</div>
<div className="description">
<p>{this.props.body}</p>
</div>
</div>
<div className="extra content">
<i className="check icon"></i>
{this.state.points} Votes
</div>
<button className="ui button"
type="submit"
onClick={this.handleClick}>Add Point</button>
</div>
</div>
}
}
You are upvoting every card because you have only one counter. A separate counter should be defined for every card.
state = {}; // dictionary-a-like state structure
handleClick = (id) => () => {
this.setState((prevState) => ({
[id]: prevState[id] ? prevState[id] + 1 : 1, // check and increment counter
}));
}
onClick={this.handleClick(post.id)} // call function with post.id as argument
{this.state[post.id] || 0} Votes // display votes for every card
Note: I assumed that every card has it's own unique id, if not - index may come handy too.
You will need one counter for each post. Currently you only have a single counter for all posts, which means that they all display that same value.
The best way to achieve this would probably be to separate your post into its own component, and have that keep track of the counter.
The following solution uses a post ID (if you have it) to create a key in a stateful points object. Then, on click, you can add to the correct points key.
state = {
points: {}
}
handleClick = postId => {
this.setState({
points: {
...this.state.points,
[postId]: (this.state.points[postId] || 0) + 1
}
})
}
const postItems = this.props.posts.map((post, index) => (
...
<div className="extra content">
<i className="check icon"></i>
{this.state.points[post.id] || 0} Votes
</div>
<button
className="ui button"
type="submit"
onClick={() => this.handleClick(post.id)}
>
Add Point
</button>
...
)

Categories