I am practising react and I have this task to build an interface where a button can add elements, another button can remove element and two oter butttons can move each element up or down stepwise like this:
I have been able to make buttons add and remove element but changing positions of elements has been giving me some headache. Below is my code:
const [inputList, setInputList] = useState([{ inputBox: '' }]);
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleRemoveClick = (index) => {
const list = [...inputList];
list.splice(index, 1);
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { inputBox: '' }]);
};
const upPosition = () => {
console.log('up');
};
const downPosition = () => {
console.log('down');
};
return (
<div>
<h3>Add Elements</h3>
<button onClick={handleAddClick}>+</button>
{inputList.map((x, i) => {
return (
<div className='box inputBox' key={i}>
<input
name='inputBox'
value={x.inputBox}
onChange={(e) => handleInputChange(e, i)}
/>
<button onClick={() => upPosition()}>
<i className='fas fa-long-arrow-alt-up'></i>
</button>
<button onClick={() => downPosition()}>
<i className='fas fa-long-arrow-alt-down'></i>
</button>
<button className='mr10' onClick={() => handleRemoveClick(i)}>
<i className='fas fa-times'></i>
</button>
</div>
);
})}
</div>
);
You can make use of splice here
Beside the shifting, you have to handle the 2 cases also, where you can't go up if the index is 0 and you can't go down if the index is inputList.length - 1
NOTE: To handle the both cases, I've disabled the buttons because that would be more meaningful to let the end user know that this button is disable so you can't go up or down.
Live Demo
const upPosition = ( index ) => {
const copy = { ...inputList[index] };
setInputList( ( oldState ) => {
const newState = oldState.filter( ( o, i ) => i !== index );
newState.splice( index - 1, 0, copy );
return newState;
} )
};
const downPosition = (index) => {
const copy = { ...inputList[index] };
setInputList( ( oldState ) => {
const newState = oldState.filter( ( o, i ) => i !== index );
newState.splice( index + 1, 0, copy );
return newState;
} )
};
You should use the splice method which can do insertions as well
const upPosition = (indexToMove) => {
if (indexToMove === 0) return;
const list = [...inputList];
const itemToMove = list.splice(indexToMove, 1)[0];
list.splice(indexToMove-1, 0, itemToMove)
setInputList(list)
};
const downPosition = (indexToMove) => {
if (indexToMove === inputList.length - 1) return;
const list = [...inputList];
const itemToMove = list.splice(indexToMove, 1)[0];
list.splice(indexToMove+1, 0, itemToMove)
setInputList(list)
};
I think you can achieve with destructuring:
const [inputList, setInputList] = useState([{ inputBox: '' }]);
const handleInputChange = (e, index) => {
const { name, value } = e.target;
const list = [...inputList];
list[index][name] = value;
setInputList(list);
};
const handleRemoveClick = (index) => {
const list = [...inputList];
list.splice(index, 1);
setInputList(list);
};
const handleAddClick = () => {
setInputList([...inputList, { inputBox: '' }]);
};
const upPosition = (i) => {
if (i > 0) {
const temp = [...inputList];
[temp[i], temp[i - 1]] = [temp[i - 1], temp[i]];
setInputList(temp);
}
};
const downPosition = (i) => {
if (i < inputList.length - 1) {
const temp = [...inputList];
[temp[i], temp[i + 1]] = [temp[i + 1], temp[i]];
setInputList(temp);
}
};
return (
<div>
<h3>Add Elements</h3>
<button onClick={handleAddClick}>+</button>
{inputList.map((x, i) => {
return (
<div className="box inputBox" key={i}>
<input
name="inputBox"
value={x.inputBox}
onChange={(e) => handleInputChange(e, i)}
/>
<button onClick={(e) => upPosition(i)}>
<i className="fas fa-long-arrow-alt-up"></i>
</button>
<button onClick={() => downPosition(i)}>
<i className="fas fa-long-arrow-alt-down"></i>
</button>
<button className="mr10" onClick={() => handleRemoveClick(i)}>
<i className="fas fa-times"></i>
</button>
</div>
);
})}
</div>
);
Related
I'm making a todo list in react js. Each time a new todo item is created, some buttons are appended next to it along with a edit input text box. I'm trying to avoid using refs but purely usestate for my case, however I can't figure out how to do it. At its current state, all edit text inputs are using the same state and that brings focus loss along with other issues. I'd highly appreciate any suggetsions.
import "./theme.css"
import * as appStyles from "./styles/App.module.css"
import * as todoStyles from "./styles/Todo.module.css"
import { useState } from "react"
const initialState = [
{
id: "1",
name: "My first ToDo",
status: "new",
},
]
export function App() {
const [numofItems, setNumofItems] = useState(2)
const [newToDo, setnewToDo] = useState('');
const [todos, setTodos] = useState(initialState);
const [editTodo, setEditTodo] = useState({name: ""});
const onAddTodo = () => {
setnewToDo("");
setTodos((old) => [
...old,
{ id: numofItems.toString(), name: newToDo, status: "new" },
])
setNumofItems(numofItems + 1);
}
deleteList = () =>{
setTodos([]);
}
const handleEdit = (id, description) =>{
let el = todos.map((item) => {if(item.id === id) {item.name = description} return item});
setTodos(el);
setEditTodo('');
}
const handleMove = (id, position) =>{
const search = obj => obj.id === id;
const todoIndex = todos.findIndex(search);
if(position === "up"){
if (todos[todoIndex - 1] === undefined) {
} else {
const newTodo1 = [...todos];
const temp1 = newTodo1[todoIndex - 1];
const temp2 = newTodo1[todoIndex]
newTodo1.splice(todoIndex - 1, 1, temp2);
newTodo1.splice(todoIndex, 1, temp1);
setTodos([...newTodo1]);
}
}
else if(position === "down"){
if (todos[todoIndex + 1] === undefined) {
} else {
const newTodo1 = [...todos];
const temp1 = newTodo1[todoIndex + 1];
const temp2 = newTodo1[todoIndex]
newTodo1.splice(todoIndex + 1, 1, temp2);
newTodo1.splice(todoIndex, 1, temp1);
setTodos([...newTodo1]);
}
}
}
const Todo = ({ record }) => {
return <li className={todoStyles.item}>{record.name}
<button className={appStyles.editButtons} onClick={() => deleteListItem(record.id)} >Delete</button>
<button className={appStyles.editButtons} onClick={() => handleEdit(record.id, editTodo.name)}>Edit</button>
<button className={appStyles.editButtons} onClick={() => handleMove(record.id, "down")}>Move down</button>
<button className={appStyles.editButtons} onClick={() => handleMove(record.id, "up")}>Move up</button>
<input className={appStyles.input}
type = "text"
name={`editTodo_${record.id}`}
value = {editTodo.name}
onChange={event => {event.persist();
setEditTodo({name: event.target.value});}}
/></li>
}
const deleteListItem = (todoid) => {
setTodos(todos.filter(({id}) => id !== todoid))
}
return (
<>
<h3 className={appStyles.title}>React ToDo App</h3>
<ul className={appStyles.list}>
{todos.map((t, idx) => (
<Todo key={`todo_${idx}`} record={t} />
))}
</ul>
<div className={appStyles.actions}>
<form>
<label>
Enter new item:
<input className={appStyles.input} type="text" name="newToDo" value={newToDo} onChange={event => setnewToDo(event.target.value)}/>
</label>
</form>
<button
className={appStyles.button}
onClick={onAddTodo}
>
Add
</button>
<br></br>
<button className={appStyles.button} onClick={this.deleteList}>
Delete List
</button>
</div>
</>
)
}
Never define components in the body of another component. It will result in unmount/mount of that element every time it's rendered.
Here is how you can split up the Todo component from you App:
const Todo = ({ record, onDelete, onEdit, onMove }) => {
const [inputValue, setInputValue] = useState(record.name);
return (
<li className={todoStyles.item}>
{record.name}
<button className={appStyles.editButtons} onClick={() => onDelete()}>
Delete
</button>
<button
className={appStyles.editButtons}
onClick={() => onEdit(inputValue)}
>
Edit
</button>
<button className={appStyles.editButtons} onClick={() => onMove("down")}>
Move down
</button>
<button className={appStyles.editButtons} onClick={() => onMove("up")}>
Move up
</button>
<input
className={appStyles.input}
type="text"
value={inputValue}
onChange={(event) => {
setInputValue(event.target.value);
}}
/>
</li>
);
};
function App() {
return (
<>
<ul className={appStyles.list}>
{todos.map((t, idx) => (
<Todo
key={`todo_${idx}`}
record={t}
onDelete={() => deleteListItem(t.id)}
onEdit={(description) => handleEdit(t.id, description)}
onMove={(position) => handleMove(t.id, position)}
/>
))}
</ul>
</>
);
}
Note: I've shown only the interesting bits, not your entire code.
If you're going to do it this way I would suggest using useReducer instead of useState.
const initialState = [
{
id: "1",
name: "My first ToDo",
status: "new",
},
]
export const types = {
INIT: 'init',
NEW: 'new'
}
export default function (state, action) {
switch (action.type) {
case types.INIT:
return initialState;
case types.NEW:
return { ...state, { ...action.item } };
default:
return state;
}
}
Now in your component you can use it like this:
import {useReducer} from 'react';
import reducer, { initialState, types } from './wherever';
const [state, dispatch] = useReducer(reducer, initialState);
const handleSubmit = (event) => {
event.preventDefault();
dispatch({ type: types.NEW, item: event.target.value });
}
I wanted to create a select-all checkbox, each product row has a checkbox, once the checkbox is clicked it will take its product id, variations, and count to calculate and display the total price of the product selected. I wanted to do like when clicking on select all, all the other checks need to tick and display the total of all product prices, I did the code for each row checkbox and it work but I am not sure how to do for select all checkbox, need help on it, below are code, and https://codesandbox.io/s/select-all-checkbox-uzmllg this is codesand box.
import "./styles.css";
import React, { useEffect, useState } from "react";
export default function App() {
const [isCheckAll, setIsCheckAll] = useState(false);
const [checkedItems, setCheckedItems] = useState(
JSON.parse(localStorage.getItem("checkedItems") || "[]")
);
useEffect(() => {
localStorage.setItem("checkedItems", JSON.stringify(checkedItems));
}, [checkedItems]);
const addChecked = (itemId, variationId, qty) => {
setCheckedItems([
...checkedItems,
{ ProductID: itemId, VariationID: variationId, Count: qty }
]);
};
const removeChecked = (itemId, variationId) => {
const toBeRemove = checkedItems.find(
(item) => item.ProductID === itemId && item.VariationID === variationId
);
if (toBeRemove) {
checkedItems.splice(checkedItems.indexOf(toBeRemove), 1);
setCheckedItems([...checkedItems]);
}
};
const getCheckedStatus = (itemId, variationId) => {
const found = checkedItems.find(
(item) => item.ProductID === itemId && item.VariationID === variationId
);
return found !== null;
};
const handleSelectAll = (e) => {
if (isCheckAll) {
//
}
};
return (
<div className="App">
{cartData.Result.map((shop) =>
shop.ShopCartList.map((cart) => (
<div key={cart.ShopID} md="12" lg="12">
{cart.productCartList.map((items) => {
return (
<div key={items.VariationID} md="12" lg="12">
<div id="additem" className="pt-5">
{items.Stock === 0 ? (
<h6 className="bg-light text-danger font-weight-bold ">
SOLD OUT
</h6>
) : (
<input
type="checkbox"
value={getCheckedStatus(
items.ProductID,
items.VariationID
)}
onChange={(e) => {
if (e.target.checked) {
addChecked(
items.ProductID,
items.VariationID,
items.Count
);
} else {
removeChecked(
items.ProductID,
items.VariationID,
items.Count
);
}
}}
/>
)}
</div>
</div>
);
})}
</div>
))
)}
<div>
<input
type="checkbox"
name="selectAll"
id="selectAll"
handleClick={handleSelectAll}
isChecked={isCheckAll}
/>
Select All
</div>
</div>
);
}
In handleSelectAll you need to set checkedItems is all your array items. You dont need isCheckAll state, you can see check all status by verify length of your checkedItems
const flattenCartData = (cartData) => {
const arr = [];
cartData.Result.forEach((shop) => {
shop.ShopCartList.forEach((cart) => {
cart.productCartList.forEach((items) => {
arr.push(items);
});
});
});
return arr;
};
export default function App() {
const [checkedItems, setCheckedItems] = useState(
JSON.parse(localStorage.getItem("checkedItems") || "[]")
);
const ITEMS = flattenCartData(cartData);
const isCheckAll = checkedItems.length === ITEMS.length;
useEffect(() => {
localStorage.setItem("checkedItems", JSON.stringify(checkedItems));
}, [checkedItems]);
const addChecked = (itemId, variationId, qty) => {
setCheckedItems([
...checkedItems,
{ ProductID: itemId, VariationID: variationId, Count: qty }
]);
};
const removeChecked = (itemId, variationId) => {
const toBeRemove = checkedItems.find(
(item) => item.ProductID === itemId && item.VariationID === variationId
);
if (toBeRemove) {
checkedItems.splice(checkedItems.indexOf(toBeRemove), 1);
setCheckedItems([...checkedItems]);
}
};
const getCheckedStatus = (itemId, variationId) => {
const found = checkedItems.find(
(item) => item.ProductID === itemId && item.VariationID === variationId
);
return found !== undefined;
};
const handleSelectAll = (e) => {
if (isCheckAll) {
setCheckedItems([]);
} else setCheckedItems([...ITEMS]);
};
return (
<div className="App">
{cartData.Result.map((shop) =>
shop.ShopCartList.map((cart) => (
<div key={cart.ShopID} md="12" lg="12">
{cart.productCartList.map((items) => {
return (
<div key={items.VariationID} md="12" lg="12">
<div id="additem" className="pt-5">
{items.Stock === 0 ? (
<h6 className="bg-light text-danger font-weight-bold ">
SOLD OUT
</h6>
) : (
<div>
<input
type="checkbox"
checked={getCheckedStatus(
items.ProductID,
items.VariationID
)}
onChange={(e) => {
if (e.target.checked) {
addChecked(
items.ProductID,
items.VariationID,
items.Count
);
} else {
removeChecked(
items.ProductID,
items.VariationID,
items.Count
);
}
}}
/>
<span>{items.ProductName}</span>
</div>
)}
</div>
</div>
);
})}
</div>
))
)}
<div>
<input
type="checkbox"
name="selectAll"
id="selectAll"
onChange={handleSelectAll}
checked={isCheckAll}
/>
Select All
</div>
</div>
);
}
I have created a codesandbox. You can check, hope it help!
I was trying to make a ToDo Site and I wanted to save if the checkbox is checked or not in LocalStorage. But whenever I am checking the button the values inside the last are vanishing and it is not even being saved in the LocalStorage.
The following is my code:
import React from "react";
import Navbar from './components/Navbar'
import '../src/App.css'
export default function TodoInput() {
const saveLocalTasks = () => {
let savedTasks = localStorage.getItem('tasks');
console.log(savedTasks)
if (savedTasks) {
return JSON.parse(localStorage.getItem('tasks'));
} else {
return [];
}
}
const [task, setTask] = React.useState('')
// const [count, setCount] = React.useState(0)
const [taskList, setTaskList] = React.useState(saveLocalTasks)
const [disable, setDisable] = React.useState(true)
const [edit, setEdit] = React.useState(true)
const [isTaskEdit, setIsTaskEdit] = React.useState(null)
React.useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(taskList))
}, [taskList]);
const updateTaskList = () => {
if (task && !edit) {
setTask('')
setTaskList(
taskList.map((item) => {
if(item.key === isTaskEdit) {
return {...item, object: task}
}
setEdit(true)
return item
}
)
)
}else {
setTaskList([...taskList, {object: task, key: Date.now(), completed: false}])
setTask('')
// setCount(count + 1)
setDisable(true)
}
}
const inputValue = e => {
setTask(e.target.value)
e.target.value === '' || task === '' || task.length === 0
?
setDisable(true)
:
setDisable(false)
}
console.log(task.length)
const deleteTaskListItem = (key) => {
const updatedList = taskList.filter((item) => {
return (
item.key !== key
)
})
setTaskList(updatedList)
// setCount(count - 1)
}
const editTask = (key) => {
let newTask = taskList.find((item) => {
return (
item.key === key
)
})
console.log(newTask)
setEdit(false)
setTask(newTask.object)
setIsTaskEdit(key)
}
const boxChecked = (key) => {
let checkedTask = taskList.map((item) => {
if (item.key === key) {
taskList.completed = !taskList.completed
}
return (
task
)
})
setTaskList(checkedTask)
}
return (
<div>
<Navbar />
<header>
<div className="todolist-border">
<div className="todo-input-form">
<input
className = "inputText"
placeholder="Add a Task"
value={task}
onChange = {inputValue}
/>
{
edit
?
<button
disabled = {disable}
onClick = {updateTaskList} className="todo-add-button">
+
</button>
:
<button className="edit-button" onClick={updateTaskList}>
<i className="fas fa-edit"></i>
</button>
}
</div>
<div>
{taskList.map((item) => {
return (
<div key = {item.key} className="todolist-div">
<input type="checkbox" className="list-checkbox" id="completed"
onChange={() => boxChecked(item.key)}
checked = {item.completed}
key = {item.key}
>
</input>
<p>{item.object}</p>
<div>
<button className="edit-button" onClick={() => editTask(item.key)}>
<i className="fas fa-edit"></i>
</button>
<button onClick={()=>deleteTaskListItem(item.key)} className="delete-button">
X
</button>
</div>
</div>
)
})}
</div>
</div>
</header>
</div>
)
}
The following error occurs when I check the checkbox:
And also I whenever I click the edit button, option to edit comes on the imput box and the add button changes to edit button. I put the state setEdit(True) after the edit button click but the following error shows up whenever I click on the edit button:
Kindly check and please correct the errors in the code
The link to the site is:
https://to-do-ist.netlify.app/
The site does not have the above code, but has the bugs I mentioned(edit button and checkbox)
The code for the site is as follows:
import React from "react";
import Navbar from './components/Navbar'
import '../src/App.css'
export default function TodoInput() {
const saveLocalTasks = () => {
let savedTasks = localStorage.getItem('tasks');
console.log(savedTasks)
if (savedTasks) {
return JSON.parse(localStorage.getItem('tasks'));
} else {
return [];
}
}
const [task, setTask] = React.useState('')
const [count, setCount] = React.useState(0)
const [taskList, setTaskList] = React.useState(saveLocalTasks)
const [disable, setDisable] = React.useState(true)
const [edit, setEdit] = React.useState(true)
const [isTaskEdit, setIsTaskEdit] = React.useState(null)
React.useEffect(() => {
localStorage.setItem('tasks', JSON.stringify(taskList))
}, [taskList]);
const updateTaskList = () => {
if (task && !edit) {
setTaskList(
taskList.map((item) => {
if(item.key === isTaskEdit) {
return {...item, object: task}
}
return item
})
)
}else {
setTaskList([...taskList, {object: task, key: Date.now()}])
setTask('')
setCount(count + 1)
setDisable(true)
}
// setEdit(true)
}
const inputValue = e => {
setTask(e.target.value)
e.target.value === '' || task === '' || task.length === 0
?
setDisable(true)
:
setDisable(false)
}
console.log(task.length)
const deleteTaskListItem = (key) => {
const updatedList = taskList.filter((item) => {
return (
item.key !== key
)
})
setTaskList(updatedList)
setCount(count - 1)
}
const editTask = (key) => {
let newTask = taskList.find((item) => {
return (
item.key === key
)
})
console.log(newTask)
setEdit(false)
setTask(newTask.object)
setIsTaskEdit(key)
}
return (
<div>
<Navbar />
<header>
<div className="todolist-border">
<div className="todo-input-form">
<input
className = "inputText"
placeholder="Add a Task"
value={task}
onChange = {inputValue}
/>
{
edit
?
<button
disabled = {disable}
onClick = {updateTaskList} className="todo-add-button">
+
</button>
:
<button className="edit-button" onClick={updateTaskList}>
<i className="fas fa-edit"></i>
</button>
}
</div>
<div>
{taskList.map((item) => {
return (
<div key = {item.key} className="todolist-div">
<input type="checkbox" className="list-checkbox">
</input>
<p>{item.object}</p>
<div>
<button className="edit-button" onClick={() => editTask(item.key)}>
<i className="fas fa-edit"></i>
</button>
<button onClick={()=>deleteTaskListItem(item.key)} className="delete-button">
X
</button>
</div>
</div>
)
})}
</div>
</div>
</header>
</div>
)
}
I'm trying to get the updated/newly created records and send it to the backend in "queryparam"
import React, { useState, useEffect } from "react";
//import { Container, Row, Col } from "reactstrap";
// import Box from "#mui/material/Box";
// import "bootstrap/dist/css/bootstrap.css";
// import "./index.css";
const Index = () => {
const [formValues, setFormValues] = useState([
{ orderno: 0, inputValue1: "", inputValue2: "", checked: false }
]);
const [isDisabled, setDisabled] = useState(false);
// const [inputVal1, setInputval1] = useState();
const [isChanged, setIsChanged] = useState([]);
const [error, setError] = useState(false);
const [orderNumber, setOrderNumber] = useState(1);
const addFormFields = () => {
// if (error) {
// setDisabled(false)
// }
// else {
// setDisabled(true)
// }
setFormValues((prevState) => [
...prevState,
{
orderno: orderNumber,
inputValue1: "",
inputValue2: "",
checked: false
}
]);
setOrderNumber((prev) => prev + 1);
};
const removeFormFields = (i) => {
let newFormValues = [...formValues];
newFormValues.splice(i, 1);
setFormValues(newFormValues);
setOrderNumber((prev) => prev - 1);
};
const onChangeFieldValue = (index, key, value) => {
setFormValues((prevState) => {
let copyState = [...prevState];
if (value?.length > 0) {
setError(false);
} else {
setError(true);
}
copyState[index][key] = value;
return copyState;
});
};
const saveFields = (e) => {
const queryparam = {
inputData: formValues
};
setIsChanged(queryparam);
setIsChanged((prevState, nextState) => {
let copyState = [];
if (prevState === nextState) {
copyState = [...prevState];
} else {
copyState = [...nextState];
}
return copyState;
});
console.log(isChanged, "lllllllll");
};
// useEffect(() => {
// saveFields()
// }, [isChanged])
return (
<>
{formValues.map((element, index) => (
<div className="form-inline" key={index}>
{/* <Container>
<Row>
<Col xs="12" sm="6"> */}
<label>{index + 1}</label>
<input
type="text"
value={element.inputVal1}
onChange={(e) =>
onChangeFieldValue(index, "inputValue1", e.target.value)
}
/>
<input
type="text"
value={element.inputVal2}
required
onChange={(e) =>
onChangeFieldValue(index, "inputValue2", e.target.value)
}
/>
{/* </Col>
<Col xs="12" sm="6">
<Box> */}
<button
className={`button ${error ? "add" : "btn-secondary"}`}
type="button"
disabled={error}
onClick={(e) => addFormFields(e)}
>
Add{console.log(isDisabled, "ooooooo", error)}
</button>
<button
type="button"
className="button remove"
onClick={() => removeFormFields(index)}
>
Remove
</button>
{/* </Box>
</Col>
</Row>
</Container> */}
</div>
))}
{/* <Row>
<Col sm="6" md={{ size: 4, offset: 2 }}>
<Box> */}
<button
type="button"
className="button save"
onClick={(e) => saveFields(e)}
>
Save
</button>
<button
type="button"
className="button remove"
//onClick={(e) => cancelFields(e)}
>
cancel
</button>
{/* </Box>
</Col>
</Row> */}
</>
);
};
export default Index;
https://codesandbox.io/s/black-fire-ixeir?file=/src/App.js:3662-3701
In the above link,
Step1 : when I add values for inputs "123" in input1 and "345" in input2.Then when I click on "Save" the values sent are {"input1":"123","input2":"345"}.
Step2: Again I try to add one row for inputs "456" in input1 and "678" in input2.Then when I click on save the values sent are {"input1":"456","input2":"678"}.
When I edit the existing row, for example the first row values and when I click on "Save" then only the first row value should be sent as the second row values hasn't changed.Also, If I add new rows then the newly added only should be sent if the existing row values aren't changed. Is there any way to send only the updated/newly created values to the backend using react hook
You could use a separate changes object to track changes by orderno property; saved during add/update/remove, and committed when submitting.
const [changes, setChanges] = useState({});
...
const addFormFields = () => {
const newItem = {
orderno: orderNumber,
inputValue1: "",
inputValue2: "",
checked: false,
type: "add"
};
setFormValues((values) => [...values, newItem]);
setChanges((changes) => ({
...changes,
[newItem.orderno]: newItem
}));
setOrderNumber((prev) => prev + 1);
};
const removeFormFields = (index) => {
const item = {
...formValues[index],
type: "remove"
};
setFormValues((values) => values.filter((el, i) => i !== index));
setChanges((changes) => ({
...changes,
[item.orderno]: item
}));
};
const onChangeFieldValue = (index, key, value) => {
const item = {
...formValues[index],
[key]: value,
type: "edit"
};
setFormValues((prevState) => {
if (value?.length > 0) {
setError(false);
const copyState = [...prevState];
copyState[index] = item;
return copyState;
} else {
setError(true);
return prevState;
}
});
setChanges((changes) => ({
...changes,
[item.orderno]: item
}));
};
const saveFields = (e) => {
const queryparam = {
inputData: Object.values(changes)
};
console.log("Changes to commit", queryparam);
setChanges({});
};
I created a simple logic: when you click on a certain block, the classname changes, but the problem is that when you click on a certain block, the classname changes and the rest of the blocks looks like this
I need to change only the name of the class that I clicked, I think I need to use the index, but I don't quite understand how to reolize it
export default function SelectGradientTheme(props) {
const resultsRender = [];
const [borderColor, setBorderColor] = useState(false);
const setBorder = () => {
setBorderColor(!borderColor)
}
const borderColorClassName = borderColor ? "selectBorder" : null;
for (var i = 0; i < GradientThemes.length; i += 3) {
resultsRender.push(
<div className={"SelectThemePictures_Separator"}>
{
GradientThemes.slice(i, i + 3).map((col, index) => {
return (
<div key={index} className={borderColorClassName} onClick={() => props.SideBarPageContent(col)|| setBorder()}>
</div>
);
})
}
</div>
)
}
return (
<div className="SelectThemeWrapper">
{resultsRender}
</div>
);
};
You can remember the selected index
Please reference the following code:
export default function SelectGradientTheme(props) {
const resultsRender = [];
const [selectedIndex, setSelectedIndex] = useState(false);
const setBorder = (index) => {
setSelectedIndex(index);
};
for (var i = 0; i < GradientThemes.length; i += 3) {
resultsRender.push(
<div className={"SelectThemePictures_Separator"}>
{
GradientThemes.slice(i, i + 3).map((col, index) => {
return (
<div key={index}
className={index === selectedIndex ? 'selectBorder' : null}
onClick={() => props.SideBarPageContent(col)|| setBorder(index)}>
</div>
);
})
}
</div>
)
}
return (
<div className="SelectThemeWrapper">
{resultsRender}
</div>
);
};