I am printing array of menu items, each has input field type number with quantity to enter for each menu item.
I'm using map function to print put all items, within is the form for each item. The only problem is when I am trying to retrieve the input value of item, the first time is taking the empty object of the useState hook that is setting the value of each item. I don't want that but only, when the value is changed. Beside that when I am clicking on arrows up and down the value of input filed is not increasing.
Can somebody help?
Here is my code of Meals.js:
import {useState, useEffect, useContext} from 'react';
import CartContext from "./store/CartContext";
const Meals = () => {
const [meals, setMeals] = useState([]);
const [meal, setMeal] = useState({});
const cartCtx = useContext(CartContext);
const fetchMeals = () => {
fetch('https://food-order-7d9f9-default-rtdb.firebaseio.com/meals.json')
.then(response => response.json() )
.then(data => {
const loadedMeals = [];
for(let key in data){
loadedMeals.push({
id: key,
meal: data[key].name,
description: data[key].description,
price: data[key].price,
quantity: 1
})
}
setMeals(loadedMeals);
})
}
useEffect(() => {
fetchMeals();
}, [])
const submitHandler = (e) => {
e.preventDefault();
cartCtx.addItem(meal)
console.log("Iz submitHandler:")
console.log(cartCtx.items)
}
const handleChange = (e, id, inputMeal, description, price) =>{
let updatedMeal = {
id: id,
meal: inputMeal,
description: description,
price: price,
quantity: +e.target.value
}
setMeal(updatedMeal)
console.log("Meal object value");
console.log(meal);
const updatedItemIndex = meals.findIndex(
i => i.id === id
)
const updatedMeals = [
...meals.slice(0, updatedItemIndex),
updatedMeal,
...meals.slice(updatedItemIndex + 1)
]
console.log("From handleChange:");
console.log(updatedMeals)
updatedMeal = {
id: "",
meal: "",
description: "",
price: "",
quantity: ""
}
}
return(
<>
{
meals.map(meal => {
return(
<div key={meal.id}>
<div>
<div>{meal.meal}</div>
<div>{meal.description}</div>
<div>{meal.price}€</div>
</div>
<div className="form-wrapper">
<form onSubmit={ e=> submitHandler(e, meal.id, meal.meal, meal.description, meal.price)}>
<input
label="Amount"
name={`${meal.id}`}
min="1"
max="5"
type="number"
value={meal.quantity}
onChange={e => handleChange(e, meal.id, meal.meal, meal.description, meal.price)}
/>
<button>+ Add</button>
</form>
</div>
</div>
)
}
)
}
</>
)
}
export default Meals;
and my demo uploaded on codesandbox.io:
https://codesandbox.io/s/wonderful-williamson-puptl?file=/src/store/CartProvider.js
Your handleChange function is wrong, On click of up and down arrow, just get the item that is being updated and update its count property.
I also updated the submitHandler.
Here is the updated Code- I hope it solves your problem .
import { useState, useEffect, useContext } from "react";
import CartContext from "./store/CartContext";
const Meals = () => {
const [meals, setMeals] = useState([]);
const cartCtx = useContext(CartContext);
const fetchMeals = () => {
fetch("https://food-order-7d9f9-default-rtdb.firebaseio.com/meals.json")
.then((response) => response.json())
.then((data) => {
const loadedMeals = [];
for (let key in data) {
loadedMeals.push({
id: key,
meal: data[key].name,
description: data[key].description,
price: data[key].price,
quantity: 1
});
}
setMeals(loadedMeals);
});
};
useEffect(() => {
fetchMeals();
}, []);
const submitHandler = (e, mealId) => {
e.preventDefault();
const updatedItemIndex = meals.findIndex((i) => i.id === mealId);
const meal = meals[updatedItemIndex];
console.log(cartCtx.items);
cartCtx.addItem({ ...meal });
};
const handleChange = (e, id, inputMeal, description, price) => {
let updatedMeal = {
id: id,
meal: inputMeal,
description: description,
price: price,
quantity: +e.target.value
};
const updatedItemIndex = meals.findIndex((i) => i.id === id);
const newMeals = [...meals];
newMeals[updatedItemIndex] = updatedMeal;
setMeals(newMeals);
};
return (
<>
{meals.map((meal) => {
return (
<div key={meal.id}>
<div>
<div>{meal.meal}</div>
<div>{meal.description}</div>
<div>{meal.price}€</div>
</div>
<div className="form-wrapper">
<form
onSubmit={(e) =>
submitHandler(
e,
meal.id,
meal.meal,
meal.description,
meal.price
)
}
>
<input
label="Amount"
name={`${meal.id}`}
min="1"
max="5"
type="number"
value={meal.quantity}
onChange={(e) =>
handleChange(
e,
meal.id,
meal.meal,
meal.description,
meal.price
)
}
/>
<button>+ Add</button>
</form>
</div>
</div>
);
})}
</>
);
};
export default Meals;
Related
I have a page in react 18 talking to a server which is passing information about how to build specific elements in a dynamic form. I am trying to figure out how to manage state in a case where there are multiple selects/multiselects in the page. Using one hook will not work separately for each dropdown field.
Code is updated with the latest updates. Only having issues with setting default values at this point. Hooks will not initially set values when given.
import { Calendar } from 'primereact/calendar';
import { Dropdown } from 'primereact/dropdown';
import { InputSwitch } from 'primereact/inputswitch';
import { InputText } from 'primereact/inputtext';
import { MultiSelect } from 'primereact/multiselect';
import React, { useEffect, useState, VFC } from 'react';
import { useLocation } from 'react-router-dom';
import { useEffectOnce } from 'usehooks-ts';
import { useAppDispatch, useAppSelector } from 'redux/store';
import Form from '../components/ReportViewForm/Form';
import { getReportParamsAsync, selectReportParams } from '../redux/slice';
export const ReportView: VFC = () => {
const location = useLocation();
const locState = location.state as any;
const dispatch = useAppDispatch();
const reportParams = useAppSelector(selectReportParams);
const fields: JSX.Element[] = [];
const depList: any[] = [];
//const defaultValList: any[] = [];
//dynamically setting state on all dropdown and multiselect fields
const handleDdlVal = (name: string, value: string) => {
depList.forEach((dep) => {
if (name === dep.dependencies[0]) {
dispatch(getReportParamsAsync(currentMenuItem + name + value));
}
});
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
//dynamically setting state on all calendar fields
const handleCalVal = (name: string, value: Date) => {
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
//dynamically setting state on all boolean fields
const handleBoolVal = (name: string, value: boolean) => {
setState((prev: any) => {
return { ...prev, [name]: value };
});
};
/* function getInitVals(values: any) {
const defaultList: any[] = [];
values.forEach((param: any) => {
defaultList.push({ name: param.name, value: param.defaultValues[0] });
});
} */
const [state, setState] = useState<any>({});
const [currentMenuItem, setCurrentMenuItem] = useState(locState.menuItem.id.toString());
useEffectOnce(() => {}), [];
useEffect(() => {
if (reportParams?.length === 0) {
dispatch(getReportParamsAsync(currentMenuItem));
}
//reload hack in order to get page to load correct fields when navigating to another report view
if (currentMenuItem != locState.menuItem.id) {
window.location.reload();
setCurrentMenuItem(locState.menuItem.id.toString());
}
}, [dispatch, reportParams, currentMenuItem, locState, state]);
//dependency list to check for dependent dropdowns, passed to reportddl
reportParams.forEach((parameter: any) => {
if (parameter.dependencies !== null && parameter.dependencies[0] !== 'apu_id') {
depList.push(parameter);
}
});
//filter dispatched data to build correct fields with data attached.
reportParams.forEach((parameter: any, i: number) => {
if (parameter.validValuesQueryBased === true) {
if (parameter.validValues !== null && parameter.multiValue) {
const dataList: any[] = [];
parameter.validValues.map((record: { value: any; label: any }) =>
dataList.push({ id: record.value, desc: record.label }),
);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<MultiSelect
options={dataList}
name={parameter.name}
value={state[parameter.name]}
onChange={(e) => handleDdlVal(parameter.name, e.value)}
></MultiSelect>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.validValues !== null) {
const dataList: any[] = [];
parameter.validValues.map((record: { value: any; label: any }) =>
dataList.push({ id: record.value, desc: record.label }),
);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<Dropdown
options={dataList}
optionValue='id'
optionLabel='desc'
name={parameter.name}
onChange={(e) => handleDdlVal(parameter.name, e.value)}
value={state[parameter.name]}
//required={parameter.parameterStateName}
placeholder={'Select a Value'}
></Dropdown>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
}
} else if (parameter.parameterTypeName === 'Boolean') {
fields.push(
<span key={i} className='col-12 mx-3 field-checkbox'>
<InputSwitch
checked={state[parameter.name]}
id={parameter.id}
name={parameter.name}
onChange={(e) => handleBoolVal(parameter.name, e.value)}
></InputSwitch>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.parameterTypeName === 'DateTime') {
//const date = new Date(parameter.defaultValues[0]);
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<Calendar
value={state[parameter.name]}
name={parameter.name}
onChange={(e) => {
const d: Date = e.value as Date;
handleCalVal(parameter.name, d);
}}
></Calendar>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
} else if (parameter.name === 'apu_id') {
return null;
} else {
fields.push(
<span key={i} className='p-float-label col-12 mx-3 field'>
<InputText name={parameter.name}></InputText>
<label className='mx-3'>{parameter.prompt.substring(0, parameter.prompt.indexOf(':'))}</label>
</span>,
);
}
});
const onSubmit = () => {
console.log(state);
};
return (
<Form onReset={null} onSubmit={onSubmit} initialValues={null} validation={null} key={null}>
{fields}
</Form>
);
};
enter code here
I cannot figure out how to add 'active' into the state of users.
For the sake of posting this here I hardcoded some users in the state, but they're supposed to be fetched from an API - and this doesn't come with 'active'. I need to be able to mark the checkboxes so that the specific user becomes active, also if active - it has to stay active when doing searches in the list through the text-input, so it doesn't reset. With what I wrote I am getting undefined for user.active. Any suggestions?
App.js
import './App.css';
import UserList from './components/UserList';
import './style/style.css';
function App() {
return (
<div className="App">
<UserList />
</div>
);
}
export default App;
UserList.js
import React, { useState, useEffect } from 'react';
function UserList() {
const [users, setUsers] = useState([
{
id: 681,
first_name: 'James',
last_name: 'Smith',
email: 'example1',
gender: 'm',
},
{
id: 3123,
first_name: 'Richard',
last_name: 'Greene',
email: 'example2',
gender: 'm',
},
{
id: 512,
first_name: 'Denise',
last_name: 'Bank',
email: 'example3',
gender: 'f',
},
{
id: 654,
first_name: 'Carl',
last_name: 'Ross',
email: 'example4',
gender: 'm',
},
]);
const [search, setSearch] = useState('');
const [filteredUsers, setFilteredUsers] = useState();
const [checkedUsers, setCheckedUsers] = useState('');
useEffect(() => {
const fetchUsers = async () => {
try {
const result = await fetch(users);
result.sort(function (a, b) {
if (a.last_name.toLowerCase() < b.last_name.toLowerCase()) return -1;
if (a.last_name.toLowerCase() > b.last_name.toLowerCase()) return 1;
else return;
});
setUsers(result);
} catch (error) {
console.log(error);
}
};
fetchUsers();
}, []);
useEffect(() => {
setFilteredUsers(
users.filter(
(user) =>
user.first_name.toLowerCase().includes(search.toLowerCase()) ||
user.last_name.toLowerCase().includes(search.toLowerCase())
)
);
}, [users, search]);
useEffect(() => {
setCheckedUsers(users.filter((user) => user.active));
}, [users]);
const changeChecked = (id) => {
users.forEach((user) => {
if (user.id === id) {
console.log(user);
if (user.active === '') {
user.active = true;
} else user.active = false;
}
});
setUsers(users);
console.log(checkedUsers);
};
return (
<div className="list-container">
<div className="search">
<input
type="text"
placeholder="Search for users"
onChange={(event) => setSearch(event.target.value)}
/>
</div>
{filteredUsers &&
filteredUsers.map((user) => (
<div
className="user-block"
key={user.id}
onClick={() => console.log(user.id, user.active)}>
<div className="details">
<h5>
{user.first_name} {user.last_name}
</h5>
<p>{user.email}</p>
</div>
<input
type="checkbox"
checked={user.active}
onClick={(event) => changeChecked(user.id)}
/>
</div>
))}
</div>
);
}
export default UserList;
A few things here:
I think you should map the user after the fetch to add the active with a default value, so it isn't undefined in any case:
useEffect(() => {
const fetchUsers = async () => {
try {
const request = await fetch(users);
const response = request.map(data => ({...data, active: true})).sort(function (a, b) {
if (a.last_name.toLowerCase() < b.last_name.toLowerCase()) return -1;
if (a.last_name.toLowerCase() > b.last_name.toLowerCase()) return 1;
else return;
});
setUsers(response);
} catch (error) {
console.log(error);
}
};
fetchUsers();
}, []);
Your filtered users is absolutely useless, you can do that with the user itself and lose the useEffect and the state variables entirely:
users.filter(user =>
user.first_name.toLowerCase().includes(search.toLowerCase()) ||
user.last_name.toLowerCase().includes(search.toLowerCase())
).map((user) => (
<div
className="user-block"
key={user.id}
onClick={() => console.log(user.id, user.active)}>
<div className="details">
<h5>
{user.first_name} {user.last_name}
</h5>
<p>{user.email}</p>
</div>
<input
type="checkbox"
checked={user.active}
onClick={(event) => changeChecked(user.id)}
/>
</div>
)
And last but not least, your changeChecked function is mutating the array. I would use .map as well instead of forEach:
const changeChecked = (id) => {
setUsers(
users.map(user => {
if (user.id === id) {
return {
...user,
active: !user.active
};
} else {
return user;
}
})
);
console.log(checkedUsers);
};
I have some code about react-country-region-selector, which is suppose to allow me to select the countries and regions, but countries do not get selected and regions remains a dash. Can someone tell me what went wrong with my code?
P.s I am using this site for my code, https://github.com/country-regions/react-country-region-selector
import { CountryDropdown, RegionDropdown } from 'react-country-region-selector';
import React, { useState } from "react";
const Locations = () => {
const [state, setState] = useState({
country: "",
region: ""
})
const selectCountry = (val) => {
setState({ state: val });
}
const selectRegion = (val) =>{
setState({ state: val });
}
const { country, region } = setState;
return(
<div>
<CountryDropdown
value={country}
onChange={(val) => selectCountry(val)} />
<RegionDropdown
country={country}
value={region}
onChange={(val) => selectRegion(val)} />
</div>
</div>
);
}
return default Locations;
What I currently have:
What I Need:
You just need to do some minor changes.
const selectCountry = (val) => {
setState({ country: val });
}
const selectRegion = (val) =>{
setState({ region: val });
}
const { country, region } = state;
return(
<div>
<CountryDropdown
value={country}
onChange={(val) => selectCountry(val)} />
<RegionDropdown
country={country}
value={region}
onChange={(val) => selectRegion(val)} />
</div>
</div>
There seems to be something wrong with the way I update state, as it gets overwritten...
import Servis from "./funkc/servisni";
import React, { useState, useEffect } from "react";
export default function ContactUpdate(props) {
const initialState = {
ime: props.item.Ime,
prezime: props.item.Prezime,
datum: props.item.Datum,
kontakt: props.item.Kontakt,
published: props.item.Published,
id: props.Id,
};
const [theItem, setTheItem] = useState();
const [message, setMessage] = useState();
useEffect(() => {
setTheItem(props.item);
console.log(theItem);
}, []);
const handleInputChange = (event) => {
const { name, value } = event.target;
setTheItem({ ...theItem, [name]: value });
console.log(theItem, props.Id);
};
the problem seems to be in the following:
const updateItem = (theItem) => {
let data = {
Ime: theItem.Ime,
Prezime: theItem.Prezime,
Kontakt: theItem.Kontakt,
Datum: theItem.Datum,
Published: true,
Id: theItem.id,
};
Servis.update(theItem.id, data)
.then(() => {
setMessage("Uspjesno ste izmijenili unos!");
})
.catch((e) => {
console.log(e);
});
};
as visible in the console.log
return (
<div className="container">
{console.log(("theItem", props.Id, theItem))}
{theItem ? (
<div className="edit-form">
<h4>Kontakt</h4>
...
<button type="submit" onClick={updateItem}>
Update
</button>
<p>{message}</p>
</div>
) : (
<div>
<br />
<p>Odaberi jedan broj...</p>
</div>
)}{" "}
</div>
);
}
The call on the updateItem function by clicking on the 'Update' button results in the error : Function DocumentReference .update() called with invalid data. Unsupported field value...
Resolved through being careful about naming variables...
</div>
<ContactUpdate item={item} id={theId} />
</div>
and then
const updateItem = () => {
let data = {
Ime: theItem.Ime,
Prezime: theItem.Prezime,
Kontakt: theItem.Kontakt,
Datum: theItem.Datum,
published: true,
id: props.id,
};
Servis.update(props.id, data)
.then(() => {
setMessage("Uspjesno ste izmijenili unos!");
})
.catch((e) => {
console.log(e);
});
};
I have the following example component that uses multiple checkboxes for choosing what items to remove from a list of objects:
import React, { useState } from "react";
import "./styles.css";
const data = [
{
name: "test1",
result: "pass"
},
{
name: "test2",
result: "pass"
},
{
name: "test3",
result: "pass"
},
{
name: "test4",
result: "pass"
},
{
name: "test5",
result: "pass"
}
];
export default function App() {
const [allChecked, setAllChecked] = useState(false);
const [isChecked, setIsChecked] = useState({});
const [formData, setFormData] = useState(data);
const handleAllCheck = e => {
setAllChecked(e.target.checked);
};
const handleSingleCheck = e => {
setIsChecked({ ...isChecked, [e.target.name]: e.target.checked });
};
const onDelete = () => {
console.log(isChecked);
const newData = data.filter(
item => !Object.keys(isChecked).includes(item.name)
);
console.log(newData);
setFormData(newData);
};
return (
<div className="App">
<div>
<label>All</label>
<input
name="checkall"
type="checkbox"
checked={allChecked}
onChange={handleAllCheck}
/>
<label />
</div>
{formData.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={allChecked ? true : isChecked[test.name]}
onChange={handleSingleCheck}
/>
</div>
))}
<button onClick={() => onDelete()}>DELETE</button>
</div>
);
}
This is mostly working, except for check all. It seems onChange will not update while using useState. I need to be able to select all the objects or uncheck some to mark for deletion.
Any help is greatly appreciated.
CodeSandbox Example: https://codesandbox.io/s/modest-hodgkin-kryco
UPDATE:
Okay, after some help from Richard Matsen,
Here is a new solution without direct DOM manipulation:
import React, { useState, useEffect } from "react";
import "./styles.css";
const data = [
{
name: "test1",
result: "pass"
},
{
name: "test2",
result: "pass"
},
{
name: "test3",
result: "pass"
},
{
name: "test4",
result: "pass"
},
{
name: "test5",
result: "pass"
}
];
export default function App() {
const [allChecked, setAllChecked] = useState(false);
const [isChecked, setIsChecked] = useState();
const [loading, setLoading] = useState(true);
const [formData, setFormData] = useState(data);
const handleAllCheck = e => {
setAllChecked(e.target.checked);
};
const handleSingleCheck = e => {
setIsChecked({ ...isChecked, [e.target.name]: e.target.checked });
};
const onDelete = () => {
const itemList = Object.keys(isChecked).map((key:any) => {
if (isChecked[key] === true) {
return key
}
})
const result = formData.filter((item:any) => !itemList.includes(item.name))
console.log(result)
setFormData(result)
}
useEffect(() => {
if (!loading) {
setIsChecked(current => {
const nextIsChecked = {}
Object.keys(current).forEach(key => {
nextIsChecked[key] = allChecked;
})
return nextIsChecked;
});
}
}, [allChecked, loading]);
useEffect(() => {
const initialIsChecked = data.reduce((acc,d) => {
acc[d.name] = false;
return acc;
}, {})
setIsChecked(initialIsChecked)
setLoading(false)
}, [loading])
return (
<div className="App">
<div>
<label>All</label>
<input
name="checkall"
type="checkbox"
checked={allChecked}
onChange={handleAllCheck}
/>
<label />
</div>
{!loading ? formData.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={isChecked[test.name]}
onChange={handleSingleCheck}
/>
</div>
)): null}
<button onClick={() => onDelete()}>DELETE</button>
</div>
);
}
codesandbox of working solution:
https://codesandbox.io/s/happy-rubin-5zfv3
The basic problem is checked={allChecked ? true : isChecked[test.name]} stops the unchecking action from happening - once allChecked is true it does not matter what value isChecked[test.name] has, the expression is always going to be true.
You should rely only on isChecked for the value, and treat changing allChecked as a side-effect.
useEffect(() => {
setIsChecked(current => {
const nextIsChecked = {}
Object.keys(current).forEach(key => {
nextIsChecked[key] = allChecked;
})
return nextIsChecked;
});
}, [allChecked]);
...
{formData.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={isChecked[test.name]}
onChange={handleSingleCheck}
/>
</div>
))}
There's also this warning cropping up
Warning: A component is changing an uncontrolled input of type checkbox to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component.
So that's basically saying don't initialize isChecked to {}, because the input's checked property is initially undefined. Use this instead,
{
test1: false,
test2: false,
test3: false,
test4: false,
test5: false,
}
or this way
const data = { ... }
const initialIsChecked = data.reduce((acc,d) => {
acc[d.name] = false;
return acc;
}, {})
export default function App() {
const [allChecked, setAllChecked] = useState(false);
const [isChecked, setIsChecked] = useState(initialIsChecked);
...
The problem with your code was how you were handling allChecked. I have made some changes to your code and it works now.
const data = [
{
name: "test1",
result: "pass"
},
{
name: "test2",
result: "pass"
},
{
name: "test3",
result: "pass"
},
{
name: "test4",
result: "pass"
},
{
name: "test5",
result: "pass"
}
];
function App() {
const [allChecked, setAllChecked] = useState(false);
// using an array to store the checked items
const [isChecked, setIsChecked] = useState([]);
const [formData, setFormData] = useState(data);
const handleAllCheck = e => {
if (allChecked) {
setAllChecked(false);
return setIsChecked([]);
}
setAllChecked(true);
return setIsChecked(formData.map(data => data.name));
};
const handleSingleCheck = e => {
const {name} = e.target;
if (isChecked.includes(name)) {
setIsChecked(isChecked.filter(checked_name => checked_name !== name));
return setAllChecked(false);
}
isChecked.push(name);
setIsChecked([...isChecked]);
setAllChecked(isChecked.length === formData.length)
};
const onDelete = () => {
const data_copy = [...formData];
isChecked.forEach( (checkedItem) => {
let index = formData.findIndex(d => d.name === checkedItem)
delete data_copy[index]
}
)
setIsChecked([])
// filtering out the empty elements from the array
setFormData(data_copy.filter(item => item));
setAllChecked(isChecked.length && isChecked.length === data.length);
};
return (
<div className="App">
<form>
<label>All</label>
<input
name="checkall"
type="checkbox"
checked={allChecked}
onChange={handleAllCheck}
/>
{ formData.map((test, index) => (
<div
key={index}
>
<label>{test.name}</label>
<input
type="checkbox"
name={test.name}
checked={isChecked.includes(test.name)}
onChange={handleSingleCheck}
/>
</div>
))
}
<label />
</form>
<button onClick={onDelete}>DELETE</button>
</div>
);
}
I think you should merge allChecked and isChecked state vars, because they represent the same thing, but your denormalizing it by creating two different vars! I suggest to keep isChecked, and modify all its entries when you press the allChecked input. Then, you can use a derived var allChecked (defined in your component or by using useMemo hook) to know if all your checks are checked or not.
Well, after some time working I came up with:
import React, { useState } from "react";
import "./styles.css";
import { useFormInputs } from "./checkHooks";
const data = [
{
name: "test1",
result: "pass"
},
{
name: "test2",
result: "pass"
},
{
name: "test3",
result: "pass"
},
{
name: "test4",
result: "pass"
},
{
name: "test5",
result: "pass"
}
];
export default function App() {
const [fields, handleFieldChange] = useFormInputs({
checkedAll: false
});
const allcheck = () => {
const checkdata = document.querySelectorAll(".checkers").length;
const numChecks = Array.from(new Array(checkdata), (x, i) => i);
numChecks.map(item => {
console.log(item);
async function checkThem() {
let element = await document.getElementsByClassName("checkers")[item];
element.click();
}
return checkThem();
});
};
return (
<div className="App">
<div>
<label>All</label>
<input name="checkall" type="checkbox" onChange={allcheck} />
<label />
</div>
{data.map((test, index) => (
<div key={index}>
<label>{test.name}</label>
<input
className="checkers"
type="checkbox"
name={test.name}
onChange={handleFieldChange}
/>
</div>
))}
</div>
);
}
Relevent codesandbox: https://codesandbox.io/s/admiring-waterfall-0vupo
Any suggestions welcomed. Also, thanks for the help guys!