I have an array of object. I want to change the text to available when checkbox is clicked and unavailable when checkbox is not clicked. The problem I am facing is when I select one item, it changes all the text to the available. How can I change the particular item text that is checked?
import "./styles.css";
import React, { useState } from "react";
const weekSchedule = [
{ day: "Sun", id: 0 },
{ day: "Mon", id: 2 }
];
export default function App() {
const [checkbox, setCheckbox] = useState(false);
const handleClick = (e) => {
setCheckbox(!checkbox);
};
return (
<div className="App">
{weekSchedule.map((day, i) => (
<div
key={i}
style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center"
}}
>
<input type="checkbox" checkbox={checkbox} onClick={handleClick} />
<h1>{day.day}</h1>`**enter code here**`
<h2>{checkbox ? "Available" : "Unavailable"}</h2>
</div>
))}
</div>
);
}
You would want to make the checkboxes controlled components: https://reactjs.org/docs/forms.html#controlled-components. Then we can use the index from the map to target changes in state.
import "./styles.css";
import React, { useState } from "react";
const weekSchedule = [
{ day: "Sun", id: 0, checked:false },
{ day: "Mon", id: 2, checked:false }
];
export default function App() {
const [checkbox, setCheckbox] = useState(weekSchedule);
const handleClick = (e,i) => {
const newWeekSchedule = [...checkbox];
newWeekSchedule[i].checked = !newWeekSchedule[i].checked;
setCheckbox(newWeekSchedule);
};
return (
<div className="App">
{checkbox.map((day, i) => (
<div
key={i}
style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center"
}}
>
<input value={checkbox[i].checked} type="checkbox" checkbox={checkbox} onClick={(e)=> handleClick(e,i)} />
<h1>{day.day}</h1>`**enter code here**`
<h2>{day.checked ? "Available" : "Unavailable"}</h2>
</div>
))}
</div>
);
}
You have only one state for checkbox. You're mapping all the elements in weekSchedule to one checkbox. If you want them to be separate, you need to keep track of them separately.
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [weekSchedule, setWeekSchedule] = useState([
{ day: "Sun", id: 0, checked: false },
{ day: "Mon", id: 2, checked: false}
]);
const handleClick = (e,id) => {
let newWeeklySchedArray = [...weekSchedule]
newWeeklySchedArray[id].checked = !e.target.checked;
setWeekSchedule(newWeeklySchedArray)
};
return (
<div className="App">
{weekSchedule.map((day, i) => (
<div
key={i}
style={{
display: "flex",
flexDirection: "row",
justifyContent: "center",
alignItems: "center"
}}
>
<input type="checkbox" onChange={(e)=>{handleClick(e,i)}} />
<h1>{day.day}</h1>`**enter code here**`
<h2>{!weekSchedule[i].checked ? "Available" : "Unavailable"}</h2>
</div>
))}
</div>
);
}
Here's a link for the demo above :)
https://codesandbox.io/s/nostalgic-jones-u11ux?file=/src/App.js
Related
I am working on a food app that adds items to a cart then calculates the total amount. I am trying to implement a reducer as opposed to having multiple instances of state hooks and I am running into this error when trying to click open my cart modal.
I know the items are being added successfully to the cart because when I add them, then inspect in the console and remove the "display: none " property from my modal and see the added food items there. For some reason its specifically when I click my cart to see the modal is when I receive the error.
The error message is saying the error is located in my app.js file where I assign define the cartFoods prop to my Cartmodal component
App.js Component
import logo from "./logo.svg";
import "./App.css";
import NavHeader from "./NavHeader";
import { useState, useEffect, useReducer } from "react";
import FoodList from "./FoodList";
import CartModal from "./CartModal";
import "animate.css";
function App() {
const [foods, setFoods] = useState([
{
food: "sushi roll",
description: "fresh tuna topped with eel sauce and avocado",
price: "14.99",
quantity: 1,
},
{
food: "pizza",
description: "baked to a crisp with mozarrella, basil and tomato sauce",
price: "9.99",
quantity: 1,
},
{
food: "special fried rice",
description: "cooked with onions , shrimp , chicken",
price: "19.99",
quantity: 1,
},
{
food: "tacos",
description:
"choice of either ,shrimp , chicken, or steak, topped with pico de gallo",
price: "15.99",
quantity: 1,
},
]);
const [totalFoodAmount, setTotalFoodAmount] = useState(0);
// const [modalDisplay, setModalDisplay] = useState("none");
const [totalPrice, setTotalPrice] = useState(0);
const [cartFoods, setCartFoods] = useState([]);
const [cartItem, setCartItem] = useState({});
const [modalDisplay, setModalDisplay] = useState("none");
const [amountValue, setAmountValue] = useState(0);
function foodReducer(state, action) {
if (action.type === "ADD_CART_ITEMS") {
return { cartFoodItems: state.cartFoodItems.concat(action.val) };
}
}
const [foodState, dispatch] = useReducer(foodReducer, {
modalDisplay: "none",
totalFoodPrice: 0,
cartFoodItems: [],
});
function setDisplay() {
dispatch({ type: "ADD_MODAL_DISPLAY" });
setModalDisplay("flex");
}
function removeModal() {
dispatch({ type: "REMOVE_MODAL_DISPLAY" });
setModalDisplay("none");
}
function setQuantity(e) {
console.log(e.target.value);
setAmountValue(e.target.value);
}
function addFood(food) {
console.log(food);
let newFoodItem = { ...food, quantity: amountValue };
// setCartFoods((prevState) => cartFoods.concat(newFoodItem));
dispatch({ type: "ADD_CART_ITEMS", val: newFoodItem });
// ask slavo specific question on why state doesnt update right away when you console.log(cartFoods) inside the function
}
useEffect(() => {
let total = foodState.cartFoodItems.reduce(function (a, b) {
return a + Number(b.quantity);
}, 0);
setTotalFoodAmount(total);
foodState.cartFoodItems.map((food) =>
setTotalPrice(totalPrice + food.price * food.quantity)
);
}, [foodState]);
return (
<div className="App">
<NavHeader cartQuantity={totalFoodAmount} setDisplay={setDisplay} />
<FoodList foodList={foods} addFood={addFood} setAmount={setQuantity} />
<CartModal
cartFoods={foodState.cartFoodItems}
display={modalDisplay}
closeModal={removeModal}
totalPrice={totalPrice}
/>
</div>
);
}
export default App;
Cart.js component
import React from "react";
export default function Cart(props) {
return (
<div
style={{
display: "flex",
marginRight: "35px",
border: "1px solid lightgray",
padding: "5px",
borderRadius: "5px",
margin: "10px",
}}
className="cart-section"
onClick={props.setDisplay}
>
<div style={{ marginRight: "20px" }}>
<h4>Your Cart</h4>
</div>
<div style={{ position: "relative", top: "0vh" }}>
<h4>Quantity: {props.cartQuantity}</h4>
</div>
</div>
);
}
CartModal.js
import React from "react";
import "animate.css";
import { CSSTransition } from "react-transition-group";
export default function CartModal(props) {
return (
<div
style={{
background: "#000000a6",
width: "100vw",
height: "100vh",
position: "fixed",
top: "0",
left: "0",
overflow: "scroll",
display: props.display,
justifyContent: "center",
alignItems: "center",
}}
>
<div
style={{
background: "white",
padding: "30px",
minHeight: "60vh",
minWidth: "75vw",
borderRadius: "10px",
}}
className="cart-modal"
>
<div style={{ display: "flex", justifyContent: "flex-end" }}>
<h3 onClick={props.closeModal}>x</h3>
</div>
<h4 style={{ textAlign: "center" }}>Your Cart</h4>
{props.cartFoods.length === 0 ? (
<h1>There are no Items in your cart</h1>
) : (
props.cartFoods.map((food, index) => (
<div
style={{
display: "flex",
justifyContent: "space-between",
borderBottom: "2px solid lightgray",
}}
key={index}
>
<div style={{ width: "10vh" }}>
<h3>{food.food}</h3>
<p>{food.price}</p>
<p>Quantity: {food.quantity}</p>
</div>
<div style={{ display: "flex" }}>
<button style={{ margin: "10px", maxHeight: "20px" }}>-</button>
<button style={{ margin: "10px", maxHeight: "20px" }}>+</button>
</div>
</div>
))
)}
<h2>Price: ${props.totalPrice}</h2>
</div>
</div>
);
}
I have been working on a drag and drop planning feature, and I am attempting to pull saved data from my backend. I have been able to successfully log the needed data, however, when I am passing it into the react-beautiful-DnD template I have been using, the data fails to appear in the items array even though it is structured exactly the same as the static starter data in the other column.
const onDragEnd = (result, columns, setColumns) => {
if (!result.destination) return;
const { source, destination } = result;
if (source.droppableId !== destination.droppableId) {
const sourceColumn = columns[source.droppableId];
const destColumn = columns[destination.droppableId];
const sourceItems = [...sourceColumn.items];
const destItems = [...destColumn.items];
const [removed] = sourceItems.splice(source.index, 1);
destItems.splice(destination.index, 0, removed);
setColumns({
...columns,
[source.droppableId]: {
...sourceColumn,
items: sourceItems
},
[destination.droppableId]: {
...destColumn,
items: destItems
}
});
} else {
const column = columns[source.droppableId];
const copiedItems = [...column.items];
const [removed] = copiedItems.splice(source.index, 1);
copiedItems.splice(destination.index, 0, removed);
setColumns({
...columns,
[source.droppableId]: {
...column,
items: copiedItems
}
});
}
};
function DragTables() {
const itemStarter = [
{ id: uuid(), travel: "Flying from NYC to MCO", brand: "American Airlines", category: "Airline", Start: "8/12/21", End: "8/12/21", points: "10000", value: "500" }
];
useEffect (() => {
fetchNewData()
},[])
const [unplannedDataSet, setUnplannedDataSet] = useState([]);
async function fetchNewData() {
// const itineraryId = 2
const response = await fetch('http://localhost:5000/planner/getUnplannedItineraryData', {
method: "POST",
headers: {jwt_token: localStorage.token}
})
const dataSet = await response.json();
setUnplannedDataSet(dataSet)
}
useEffect (() => {
fetchPlannedData()
},[])
const [plannedDataSet, setPlannedDataSet] = useState([]);
async function fetchPlannedData() {
// const itineraryId = 2
const response = await fetch('http://localhost:5000/planner/getPlannedItineraryData', {
method: "POST",
headers: {jwt_token: localStorage.token}
})
const plannedDataSet = await response.json();
setPlannedDataSet(plannedDataSet)
}
const parsedData = [];
unplannedDataSet.forEach(element => {
parsedData.push({
id: element.id,
brand: element.brand
});
});
**const columnsFromBackend = {
//This does not
[uuid()]: {
name: "Itinerary",
items: plannedDataSet
},
//This works
[uuid()]: {
name: "Travel Options",
items: itemStarter
}
};**
const [columns, setColumns] = useState(columnsFromBackend);
//DND component
return (
<div>
<div style={{ display: "flex", justifyContent: "space-around", height: "100%", marginTop: 8}}>
<DragDropContext
onDragEnd={result => onDragEnd(result, columns, setColumns)}
>
{Object.entries(columns).map(([columnId, column], index) => {
return (
<div
style={{
display: "block",
flexDirection: "column",
alignItems: "center",
fontSize: 2
}}
key={columnId}
>
<h4 style={{ display: "flex",
justifyContent: "center",}}>{column.name}</h4>
<div style={{ display: "flex",
justifyContent: "center",
marginTop: 4}}>
<Droppable droppableId={columnId} key={columnId}>
{(provided, snapshot) => {
return (
<div
{...provided.droppableProps}
ref={provided.innerRef}
>
{column.items.map((item, index) => {
return (
<Draggable
key={item.id}
draggableId={item.id}
index={index}
>
{(provided, snapshot) => {
return (
<div className="snapshot"
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}
>
<p style={{paddingLeft: 5, paddingTop: 1}}> <div style={{borderBottom: "1px solid white" }}><strong>{item.travel}</strong> </div>
<strong>Brand:</strong> {item.brand} | <strong># of Points:</strong> {item.points} | <strong>Point Value:</strong> ${item.value}
<br></br><strong>Category:</strong> {item.category} | <strong>Start Date:</strong> {item.Start} | <strong>End Date:</strong> {item.End}</p>
<p></p>
</div>
);
}}
</Draggable>
);
})}
{provided.placeholder}
</div>
);
}}
</Droppable>
</div>
</div>
);
})}
</DragDropContext>
</div>
</div>
);
}
export default DragTables;```
The reason why your code is not working is that you put const columnsFromBackend nested in your React DragTables Component. When you do this JavaScript will compile the code each time, producing a new copy of the columnsFromBackend Object, and React will not initialize the useEffect right, causing an infinite loop. Just put columnsFromBackend in the root scope and it will work right, but you will need to sync with the database.
You should not pass an object into useEffect, only a plain-old-data-type, but I think a string is okay but not an Object. I personally use a timer to autosave my state for my Chrome Extension. I have a useState number to switch tabs/views with my nav bar, and in each tab/view the timer updates a different part of my state relevant to the mode. You can also use a boolean useState and each time you change from true to false or false to true it saves.
am stuck with a problem when I click on like button I want it increment by +1, can anyone tell me how can I do it, I try it but I can't solve it.
below I share my all code that I used to make my small application. if you have question free feel to ask me.
Music.js
This is my music form where I wrote my whole code.
import React, { useState, useRef, useEffect } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Typography from '#material-ui/core/Typography';
import Button from '#material-ui/core/Button';
import IconButton from '#material-ui/core/IconButton';
import MenuIcon from '#material-ui/icons/Menu';
import ExitToAppIcon from '#material-ui/icons/ExitToApp';
import RadioIcon from '#material-ui/icons/Radio';
import firebase from '../Firebase';
import SearchBar from "material-ui-search-bar";
import { useHistory } from 'react-router-dom';
import { Container, Input, TextField } from '#material-ui/core';
import './Music.css';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableContainer from '#material-ui/core/TableContainer';
import TableHead from '#material-ui/core/TableHead';
import TableRow from '#material-ui/core/TableRow';
import Paper from '#material-ui/core/Paper';
import ThumbUpAltIcon from '#material-ui/icons/ThumbUpAlt';
// import { useSelector } from 'react-redux';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
menuButton: {
marginRight: theme.spacing(2),
},
title: {
flexGrow: 1,
},
search: {
marginTop: 30,
},
table: {
minWidth: 650,
marginBottom: 10,
},
cells: {
marginTop: 50,
},
thumb: {
color: '#e75480',
},
name: {
color: 'blue',
padding: 10,
fontSize: 20,
},
audios: {
display: 'flex',
margin: 'auto',
height: 50,
width: 500,
alignItems: 'center'
},
icon: {
fontSize: 40,
color: '#e75480',
cursor:'pointer'
}
}));
const Music = () => {
const history = useHistory();
const inputRef = useRef(null);
const [search, setSearch] = useState("");
const [like, setLike] = useState(false);
const [music,setMusics] = useState([
{
id:"1",
name:"Arijit singh",
audiosrc:"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
},
{
id:"2",
name:"Atif Aslam",
audiosrc:"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
},
{
id:"3",
name:"Sonu Nigam",
audiosrc:"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
},
{
id:"4",
name:"Neha kakkar",
audiosrc:"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
},
])
const likeButton = (id)=>{
const likebuttons = music.find((curElem)=>{
return curElem.id == id
})
setLike({likebuttons:like+1})
console.log(likebuttons);
}
console.log(search);
// Logout Functionality
const Logout = () => {
firebase.auth().signOut().then(() => {
alert("Logout Successfull...");
history.push('/');
}).catch((error) => {
console.log(error);
});
}
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="static" style={{ width: '100%' }}>
<Toolbar>
<IconButton edge="start" className={classes.menuButton} color="inherit" aria-label="menu">
<RadioIcon style={{ fontSize: "30px" }} /> React Music
</IconButton>
<Typography variant="h6" className={classes.title}>
</Typography>
<Button color="inherit" onClick={Logout}> <ExitToAppIcon /> Logout </Button>
</Toolbar>
</AppBar>
<Container>
<SearchBar className={classes.search}
value={search}
onChange={(newValue) => setSearch(newValue)}
/>
<Table className={classes.table} aria-label="simple table">
<TableBody>
{music && music.map(mus=>{
return(
<TableRow>
<TableCell style={{ display: 'flex', justifyContent: 'space-around' }}>
<div>
<h3>{like} <ThumbUpAltIcon className={classes.icon} onClick={()=>likeButton(music.id)} /> {mus.name}</h3>
</div>
<div>
<audio ref={inputRef} src={mus.audiosrc} className={classes.audios} controls />
</div>
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</Container>
</div>
);
}
export default Music;
Make following changes in your code:
const [like, setLike] = useState(false);
to
const [like, setLike] = useState(0);
and
setLike({likebuttons:like+1})
to
setLike(like+1);
and try again.
If you want to have like count for all music data,
First you should change like state to store object
const [like, setLike] = useState({});
Change your like button function to store data in object
const likeButton = (musicId)=>{
setLike({...like, like[musicId]: like[musicId] + 1 || 1 })
}
Now change how you are showing like count as below:
<div>
<h3>{like[music.id]} <ThumbUpAltIcon className={classes.icon} onClick={()=>likeButton(music.id)} /> {mus.name}</h3>
</div>
first, you should change your states.
each music has it's own like number, so you can't use 1 like state for all.
each item in your music array should have a value to store it's own like
numbers.
something like :
const [music,setMusics] = useState([
{
id:"1",
name:"Arijit singh",
audiosrc:"https://uploa...",
likeNumbers:0,
},
...
]
then your onClick should iterate the music array, find the clicked item and change it's likeNumbers value.
something like this:
cosnt handleClick = (id) => {
setMusic((prevState) => prevState.map((item) => {
if (item.id === id ) {
return {...item, likeNumbers:likeNumbers + 1 }
} else {
return item
}
})
}
to be clear:
first you should take the last version of your state, then in the process of iterating, find the clicked item and update it. to avoid mutate your state ( because items are objects ), you should make a copy first, then changed it. I mean here:
return {...item, likeNumbers:likeNumbers + 1 }
after all a part of your jsx code should be changed to :
<h3>{mus.likeNumber} <ThumbUpAltIcon className={classes.icon} onClick={()=>likeButton(music.id)} /> {mus.name}</h3>
First you need to make type as number instead of boolean
const [like, setLike] = useState(0);
and then
const likeButton = (id)=>{
const likebuttons = music.find((curElem)=>{
return curElem.id == id
})
setLike(likebuttons+1);
console.log(likebuttons);
}
Or
you can add no. of likes in same array object and just update that like field
You can check below example created for you. I hope it will help you.
It's having only like functionality
import "./styles.css";
import React, { useState } from "react";
export default function App() {
const [likedSong, setLikedSong] = useState({
likes: 0,
id: 0
});
const [music, setMusics] = useState([
{
id: "1",
name: "Arijit singh",
audiosrc:
"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
likes: 0
},
{
id: "2",
name: "Atif Aslam",
audiosrc:
"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
likes: 0
},
{
id: "3",
name: "Sonu Nigam",
audiosrc:
"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
likes: 0
},
{
id: "4",
name: "Neha kakkar",
audiosrc:
"https://upload.wikimedia.org/wikipedia/commons/1/15/Bicycle-bell.wav",
likes: 0
}
]);
const handleLike = (list) => {
if (likedSong.id === list.id) {
setLikedSong({ ...likedSong, id: list.id, likes: ++likedSong.likes });
} else {
setLikedSong({ ...likedSong, id: list.id, likes: 0 });
}
};
return (
<div className="App">
{music.map((mus) => (
<div key={mus.id} className="music-list">
<div>
{mus.id === likedSong.id && (
<span className="no-likes">{likedSong.likes}</span>
)}
<span className="btn-like" onClick={() => handleLike(mus)}>
Like
</span>
{mus.name}
</div>
</div>
))}
</div>
);
}
Live working demo
I have 3 DIVs, dynamically created. My target is: when any div is clicked to add active class to it, and of course if any other has that active class to remove it. How can I achieve that?
import React, { useState } from "react";
import "./styles/App.css";
import { Container, Box, Typography, makeStyles } from "#material-ui/core";
const useStyles = makeStyles({
mainBox: {
display: "flex",
justifyContent: "space-evenly"
},
mybox: {
backgroundColor: "#9fa8da",
padding: "40px",
color: "#fff",
maxWidth: 300
}
});
function App() {
const clasess = useStyles();
const [active, setactive] = useState("");
const mydata = [
{
id: 1,
name: "Ganesh",
des: "UI Developer"
},
{
id: 2,
name: "Suresh",
des: "Accountant"
},
{
id: 3,
name: "Srikanth",
des: "Digital"
}
];
const onClick = index => {
setactive("active");
};
return (
<Container>
<Box className={clasess.mainBox}>
{mydata.map((val, index) => {
return (
<>
<Box
boxShadow={1}
key={index}
onClick={e => {
onClick(index);
}}
className={active}
>
<Typography variant="h4">{val.name}</Typography>
<Typography>{val.des}</Typography>
</Box>
</>
);
})}
</Box>
</Container>
);
}
export default App;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I have 3 DIVs, dynamically created. My target is: when any div is clicked to add active class to it, and of course if any other has that active class to remove it. How can I achieve that?
I have 3 DIVs, dynamically created. My target is: when any div is clicked to add active class to it, and of course if any other has that active class to remove it. How can I achieve that?
Try to check when active id is the clicked id:
import React, { useState } from "react";
import "./styles/App.css";
import { Container, Box, Typography, makeStyles } from "#material-ui/core";
const useStyles = makeStyles({
mainBox: {
display: "flex",
justifyContent: "space-evenly"
},
mybox: {
backgroundColor: "#9fa8da",
padding: "40px",
color: "#fff",
maxWidth: 300
}
});
function App() {
const clasess = useStyles();
const [active, setActive] = useState();
const mydata = [
{
id: 1,
name: "Ganesh",
des: "UI Developer"
},
{
id: 2,
name: "Suresh",
des: "Accountant"
},
{
id: 3,
name: "Srikanth",
des: "Digital"
}
];
const onClick = id => {
setActive(id);
};
return (
<Container>
<Box className={clasess.mainBox}>
{mydata.map((val, index) => {
return (
<>
<Box
boxShadow={1}
key={index}
onClick={e => {
onClick(val.id);
}}
className={val.id == id ? active : deactive}
>
<Typography variant="h4">{val.name}</Typography>
<Typography>{val.des}</Typography>
</Box>
</>
);
})}
</Box>
</Container>
);
}
export default App;
You already managed on your Box component to add an "active" classname when one of them is Clicked.
But, you need to add some style or something to show for those "active" elements.
Inside of useStyle add the class active and test it out with some styling:
i.e)
const useStyles = makeStyles({
mainBox: {
display: "flex",
justifyContent: "space-evenly"
},
mybox: {
backgroundColor: "#9fa8da",
padding: "40px",
color: "#fff",
maxWidth: 300
},
active {
backgroundColor: "red"
}
});
I'm not sure if you need to add "active" class using classes, something like :
<Box
boxShadow={1}
key={index}
onClick={e => {
onClick(index);
}}
className={classes.active}
>
<Typography variant="h4">{val.name}</Typography>
<Typography>{val.des}</Typography>
</Box>
I am trying to delete div section without using state, how to remove this? I tried by using unmountComponentAtNode but showing the error
unmountComponentAtNode(): The node you're attempting to unmount was rendered by React and is not a top-level container. Instead, have the parent component update its state and rerender in order to remove this component.
Code:
import 'rc-slider/assets/index.css';
import 'rc-tooltip/assets/bootstrap.css';
import React from 'react';
import Tooltip from 'rc-tooltip';
import Slider from 'rc-slider';
import { withStyles } from '#material-ui/core/styles';
import Icon from '#material-ui/core/Icon';
import { unmountComponentAtNode } from 'react-dom';
const createSliderWithTooltip = Slider.createSliderWithTooltip;
const Range = createSliderWithTooltip(Slider.Range);
const Handle = Slider.Handle;
const marks = {
0: <strong>0°C</strong>,
26: '26°C',
37: '37°C',
50: '50°C',
100: {
style: {
color: 'red',
},
label: <strong>100°C</strong>,
},
};
const handle = (props) => {
const { value, dragging, index, ...restProps } = props;
return (
<Tooltip
prefixCls="rc-slider-tooltip"
overlay={value}
visible={dragging}
placement="top"
key={index}
>
<Handle value={value} {...restProps} />
</Tooltip>
);
};
class StepSlider extends React.Component {
constructor(props) {
super(props);
this.state = { sliderValues: [80] };
this.onDelEvent = this.onDelEvent.bind(this)
}
handleChange = sliderValues => {
this.setState({ sliderValues });
};
onDelEvent = (e) => {
console(e)
var object = this.refs.slider;
unmountComponentAtNode(object);
document.body.removeChild(object);
}
render() {
const { classes } = this.props;
const { sliderValues } = this.state;
return (
<div className="row" style={{ margin: '50px' }} ref="slider" id="slider">
<div className="col-md-11">
<div className="box-header" style={{ textAlign: 'center', fontSize: '20px' }}><strong>Project NPV: $2.98M</strong></div>
<p style={{ position: 'absolute', color: 'pink' }}>kjh</p>
{/* <Slider min={0} max={100} marks={marks} defaultValue={sliderValues} onChange={this.handleChange} handle={handle} tipFormatter={value => `${value}%`}/> */}
<Slider
min={0} max={100} marks={marks} defaultValue={sliderValues} onChange={this.handleChange} handle={handle} tipFormatter={value => `${value}%`}
trackStyle={{ backgroundColor: 'blue', height: 15 }}
handleStyle={{
borderColor: 'red',
height: 35,
width: 35,
marginLeft: -14,
marginTop: -9,
backgroundColor: 'white',
}}
railStyle={{ backgroundColor: 'black', height: 15 }}
/>
</div>
<div className="col-md-1">
<Icon className={classes.icon} color="primary" onClick={this.onDelEvent.bind(this)} style={{ marginTop: '45px' }}>
remove_circle</Icon>
{/* <div style={wrapperStyle}>
<p>Range with custom handle</p>
<Range min={0} max={20} defaultValue={[3, 10]} tipFormatter={value => `${value}%`} />
</div> */}
</div>
</div>
)
}
}
export default withStyles({ withTheme: true })(StepSlider);
I suggest the following pattern for dynamic removal of sliders:
Slider.js
const Slider = ({ id, onRemove }) => (
<div className="slider">
<button onClick={() => onRemove(id)} />
</div>
);
export default Slider;
StepSlider.js
import Slider from './Slider';
class StepSlider extends React.Component {
state = {
sliders: [
{id: 1, value: ...},
{id: 2, value: ...},
...
]
}
handleRemoveSlider = id => {
this.setState(prevState => ({
sliders: [...prevState.sliders.filter(slider => slider.id !== id)]
}))
}
render() {
this.state.sliders.map(slider => (
<Slider id={slider.id} onRemove={this.handleRemoveSlider} />
))
}
}
import 'rc-slider/assets/index.css';
import 'rc-tooltip/assets/bootstrap.css';
import React from 'react';
import Tooltip from 'rc-tooltip';
import Slider from 'rc-slider';
import { withStyles } from '#material-ui/core/styles';
import Icon from '#material-ui/core/Icon';
const createSliderWithTooltip = Slider.createSliderWithTooltip;
const Range = createSliderWithTooltip(Slider.Range);
const Handle = Slider.Handle;
const marks = {
0: '5%',
10: '6%',
20: '7%',
30: '8%',
40: '9%',
50: '10%',
60: '11%',
70: '12%',
80: '13%',
90: '14%',
100: '15%'
};
const handle = (props) => {
const { value, dragging, index, ...restProps } = props;
return (
<Tooltip
prefixCls="rc-slider-tooltip"
overlay={value}
visible={dragging}
placement="top"
key={index}
>
<Handle value={value} {...restProps} />
</Tooltip>
);
};
const handleStyle = {
borderColor: 'red',
height: 28,
width: 28,
marginLeft: -14,
marginTop: -8,
backgroundColor: 'white',
}
class StepSlider extends React.Component {
constructor() {
super()
this.state = {
sliders: [
{ id: 1, title: 'Discount Rate', value: '5' },
{ id: 2, title: 'Total Volume', value: '10' },
{ id: 3, title: 'Avg Sales Rate', value: '50' }
]
}
this.handleRemoveSlider = this.handleRemoveSlider.bind(this);
this.onChange=this.onChange.bind(this)
}
onChange=(e)=>{
let inputValue = e;
let statusCopy = Object.assign({}, this.state);
statusCopy.value = inputValue;
this.setState(statusCopy);
}
handleRemoveSlider = id => {
this.setState(prevState => ({
sliders: [...prevState.sliders.filter(slider => slider.id !== id),
],
}))
}
render() {
return (
this.state.sliders.map(slider => (
<div>
<Button id={slider.id} onRemove={this.handleRemoveSlider} title={slider.title} value={slider.value} onChange={this.onChange}/>
</div>
))
)
}
}
export default StepSlider;
const Button = ({ id, onRemove, value, title,onChange }) => (
<div className="row" style={{ margin: '50px' }} id={id}>
<div className="col-md-1">
{title}
</div>
<div className="col-md-10">
<Slider min={0} max={100} handle={handle}
defaultValue={value} marks={marks}
tipFormatter={value => `${value}%`}
trackStyle={{ backgroundColor: 'blue', height: 15 }}
handleStyle={handleStyle}
railStyle={{ backgroundColor: 'black', height: 15 }}
onChange={onChange}
/>
</div>
<div className="col-md-1">
<button onClick={() => onRemove(id)} style={{ backgroundColor: '#1a237e', color: 'white' }}>X</button>
</div>
</div>
);
Actually this is working, i mean deleting slider by passing its respective id but state is not updating and i wanna update the particular slider value onchanging it. please check and help me