React prop value changing though it is readonly - reactjs

I have a parent component - RoomSettings.tsx where I am passing a prop, room to a child component RoomSettingsStreams
RoomSettings.tsx
export default function RoomSettings() {
const { id } = useParams() as { id: string };
const [room, setRoom] = useState<Room | null>({
streams: [
{
name: "Somthing",
other: "Others",
},
{
name: "Somtehing 2",
others: "Sasdfasd",
},
],
});
return (
<div className="h-screen flex overflow-hidden bg-slate">
<RoomSettingsStreams initStreams={room ? [...room.streams] : []} />
</div>
);
}
RoomSettingStreams.tsx
interface RoomSettingsStreamsProps {
initStreams: Stream[] | null;
}
interface Stream {
name: string;
other: string;
}
export default function RoomSettingsStreams({
initStreams,
}: RoomSettingsStreamsProps) {
const [init, setInit] = useState<Stream[]>([]);
const [streams, setStreams] = useState<Stream[]>([]);
const [token, setToken] = useState("");
const [edit, setEdit] = useState(false);
const [message, setMessage] = useState({
message: "",
show: false,
type: "error",
});
const editRoom = () => {};
useEffect(() => {
if (initStreams) {
setStreams([...initStreams]);
setInit([...initStreams]);
}
}, [initStreams]);
return (
<div className="bg-card rounded-lg border border-gray-800">
{streams.map((e, i) => {
return (
<div className="p-6 pb-10 sm:mt-5 space-y-6 sm:space-y-5" key={i}>
<div className="flex">
<StreamLabel text={`Stream ${i + 1}`} />
</div>
{/* Item */}
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start">
<div>
<SettingsLabel text="Stream Title" />
</div>
<div className="mt-2 sm:mt-0 col-span-2">
{edit ? (
<Input
className="text-gray-200"
type="text"
placeholder="Enter stream title"
value={e.stream_title}
onChange={(f) => {
const newStreams = streams.map((e, j) => {
if (i === j) e.name = f.currentTarget.value;
return e;
});
setStreams([...newStreams]);
}}
/>
) : (
<p className="text-gray-200">{e.name}</p>
)}
</div>
<div className="mt-1 sm:mt-0 sm:col-span-2"></div>
</div>
{/* Item */}
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start">
<div>
<SettingsLabel text="Publishing Method" />
</div>
<div className="mt-2 sm:mt-0 col-span-2">
{edit ? (
<Listbox
options={["OBS-WebRTC", "Browser", "RTMP"]}
selected={e.other}
setSelected={(f: any) => {
const newStreams = streams.map((e, j) => {
if (i === j) e.other = f;
return e;
});
setStreams([...newStreams]);
}}
/>
) : (
<p className="text-gray-200">{e.publishing_method}</p>
)}
</div>
{/* OBS-WebRTC Keys */}
<SettingsLabel text="OBS Stream Name" />
<div className="mt-1 sm:mt-0 sm:col-span-2">
<InputClipboard
className="text-blue-brand"
type="text"
placeholder=""
value={e.name}
onClick={() => {
navigator.clipboard.writeText(e.name);
}}
readOnly={true}
/>
</div>
</div>
</div>
);
})}
<div className="p-6">
<AddItem text="Add another stream" />
</div>
<RoomSettingsEditButton
edit={edit}
setEdit={setEdit}
onCancel={() => {
setEdit(false);
if (!init) return;
setStreams([...init]);
}}
onSuccess={async () => {
editRoom();
setEdit(false);
}}
/>
</div>
);
}
When I am calling setStreams in RoomSettingsStreams.tsx it changes the value of the prop initStreams as well as the state variable init. I am using the spread operator so that there is no referential equality and I have checked with streams === initStreams which returns false but still the change in streams is reflected in the initStreams prop, any ideas how can I prevent it and what am I doing wrong?

Related

How can I maintain the order of adding items in react web app?

How can I create an order of adding items. I should be able to add one after the other item during on click. By default it should display the Textarea first and then blockquote ( see below )
a) When a user click on Text area button, it should add one after the blockquote.
b) Then when the user clicks on Code area button, it should add after Textarea. Could someone please advise ?
CSB link: https://codesandbox.io/s/distracted-worker-26jztf?file=/src/App.js
Something similar >> Expected behaviour: https://jsfiddle.net/nve8qdbu/8/
import "./styles.css";
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
import { useForm } from "react-hook-form";
const blogListData = [
{
id: 1,
heading: "React state",
date: "22-May-2022",
tag: "React",
count: "3"
},
{
id: 2,
heading: "Cypress testing detailss",
date: "22-May-2022",
tag: "Cypress",
count: "5"
}
];
const Admin = () => {
const [createImageTag, setImageTag] = useState("");
const [fields, setFields] = useState([{ value: null }]);
const [createCode, setCreateCode] = useState([{ value: null }]);
const [blogList, setBlogList] = useState([]);
const {
register,
handleSubmit,
formState: { errors },
reset
} = useForm();
useEffect(() => {
setBlogList(blogListData);
}, []);
function handleChangeTextArea(i, event) {
const values = [...fields];
values[i].value = event.target.value;
setFields(values);
}
function handleChangeCode(i, event) {
const codeValues = [...createCode];
codeValues[i].value = event.currentTarget.innerText;
setCreateCode(codeValues);
}
function handleTextAreaAdd() {
const values = [...fields];
values.push({ value: null });
setFields(values);
}
function handleCodeAreaAdd() {
const codeValues = [...createCode];
codeValues.push({ value: null });
setCreateCode(codeValues);
}
function handleImageAreaAdd() {
const image = [...createImageTag];
image.push({ value: null });
setCreateCode(image);
}
function handleRemoveText(i) {
const values = [...fields];
values.splice(i, 1);
setFields(values);
}
function handleRemoveCode(i) {
const codeValues = [...createCode];
codeValues.splice(i, 1);
setCreateCode(codeValues);
}
const handleLogout = () => {
localStorage.removeItem("loginEmail");
};
return (
<div id="App">
<div className="parent">
<div className="adminSection">
<h1>Create a new blog</h1>
<div className="row">
<div className="logout">
<img
src="/images/logout.png"
alt="Logout"
onClick={handleLogout}
></img>
</div>
<div className="createBlogSection">
<div className="row">
<button
onClick={() => handleTextAreaAdd()}
className="textAreaBtn"
>
Text Area
</button>
<button
onClick={() => handleCodeAreaAdd()}
className="codeAreaBtn"
>
Code Area
</button>
<button
onClick={() => handleImageAreaAdd()}
className="imageAreaBtn"
>
Add Image
</button>
</div>{" "}
<br></br>
<div className="row">
{fields.map((field, idx) => {
return (
<div key={`${field}-${idx}`} className="dtextArea">
<button
type="button"
onClick={() => handleRemoveText(idx)}
className="closeElement"
>
X
</button>
<textarea
type="text"
id="blogtext"
placeholder="Enter your text here"
className="defaultTextArea"
{...register("blogtext", {
required: true,
minLength: {
value: 25,
message: "Minimum length of 25 letters"
}
})}
value={field.value || ""}
onChange={(e) => handleChangeTextArea(idx, e)}
/>
<span className="validationmsg">
{errors.blogtext &&
errors.blogtext.type === "required" && (
<span>Blog text is required !</span>
)}
{errors.blogtext && (
<span>{errors.blogtext.message}</span>
)}
</span>
</div>
);
})}
</div>
<div className="row">
{createCode.map((code, idx) => {
return (
<div key={`${code}-${idx}`} className="dCodeArea">
<button
type="button"
onClick={() => handleRemoveCode(idx)}
className="closeElement"
>
X
</button>
<blockquote
type="text"
id="blogCode"
contentEditable="true"
className="codehighlight"
placeholder="Enter your code here"
{...register("blogCode", {
required: true
})}
value={code.value || ""}
onInput={(e) => handleChangeCode(idx, e)}
/>
</div>
);
})}
</div>
<div className="row">
</div>
<div className="row">
<div className="submitSection">
<input type="submit" className="submitBtn" />
</div>
</div>
</div>
</div>
</div>
<div className="blogListSection">
<h1>Edit blogs</h1>
<div className="row">
<div className="editBlogSection">
{blogList.map(({ id, heading, count }) => (
<a
key={id}
href="https://www.testingsite.com/"
className="blogitems"
>
<pre>
<span>{count}</span> {heading}
</pre>
</a>
))}
</div>
</div>
</div>
</div>
</div>
);
};
export default Admin;
react is designed for components . each of your list elements should be refactored by a component.then it would be easier. i think a single react component could do the trick

Directus and React data not submitting to API

I'm trying to submit reviews to a directus app but the review is not getting added to the data.
I can retrieve the data but cannot add.
I've checked all permissions and set the directus app to public permissions.
cannot figure out what the problem could be.
can anyone advise what could be wrong?
the api call:
import axios from 'axios';
const url = 'https://pwsbbqhj.directus.app/items/Reviews';
export const readReviews = () => axios.get(url);
export const createReview = (newReview) => axios.post(url, newReview);
the data retrieval :
import React, { useState, useEffect } from 'react';
import * as api from '../../../api';
import { FaStar } from 'react-icons/fa';
const colors = {
orange: '#e42320',
grey: '#a9a9a9',
};
function Ratings() {
const stars = Array(5).fill(0);
const [currentValue, setCurrentValue] = React.useState(0);
const [hoverValue, setHoverValue] = React.useState(undefined);
const handleClick = (value) => {
setCurrentValue(value);
};
const handleMouseOver = (value) => {
setHoverValue(value);
};
const [review, setReview] = useState({});
const [reviews, setReviews] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await api.readReviews();
setReviews(result.data.data);
};
fetchData();
}, []);
const createReview = async (review) => {
try {
const data = await api.createReview({ review });
setReview([...reviews, data.data]);
} catch (error) {
console.log(error);
}
};
let [reviewCount, setreviewCount] = useState([]);
const setCountFxn = (no) => {
setReview(no);
console.log(no);
};
return (
<div className='col-md-12 row-testimonials'>
<div className='reviews-heading pb-5 pt-5'>
<h2>REVIEWS FROM OUR CUSTOMERS</h2>
</div>
<div
className='themesflat-carousel-box has-bullets bullet-circle has-buttons has-arrows clearfix'
data-gap={30}
data-column={3}
data-column2={2}
data-column3={1}
data-auto='false'
>
<div className='owl-carousel owl-theme'>
{reviews.map((review) => (
<div className='themesflat-testimonials style-2 align-center clearfix' key={review.id}>
<div className='testimonial-item'>
<div className='inner'>
<div className='thumb'>
<img src='assets/img/testimonials/customer-1-90x90.jpg' alt='altimage' />
</div>
<blockquote className='text'>
<div className='name-pos clearfix'>
<h6 className='name'>{review.Title}</h6>
<span className='position'></span>
</div>
<p>{review.Body}</p>
<div className='list-star'>
{Array.from({ length: review.Rating }).map((i) => (
<FaStar key={i} size={18} color={colors.orange} />
))}
</div>
<div className='m-2'>
By: <span className='name'>{review.Name}</span>
</div>
</blockquote>
</div>
</div>
</div>
))}
</div>
</div>
<div className='bg-black'>
<form>
<div className='mb-5'>
<h2>RATE OUR SERVICE</h2>
<div className='mt-5 mb-5'>
{stars.map((_, index) => {
return (
<FaStar
key={index}
size={20}
style={{
marginRight: 10,
cursor: 'pointer',
}}
color={(hoverValue || currentValue) > index ? colors.orange : colors.grey}
onClick={() => {
setReview({ ...review, Rating: index + 1 });
}}
onMouseOver={() => handleMouseOver(index + 1)}
/>
);
})}
</div>
<div id='message'></div>
<div>
<input
type='text'
placeholder='Your Name'
required
value={review.Name}
onChange={(e) => setReview({ ...review, Name: e.target.value })}
className='wpcf7-form-control'
/>
</div>
<div>
<input
type='text'
placeholder='Review Title'
required
value={review.Title}
onChange={(e) => setReview({ ...review, Title: e.target.value })}
className='wpcf7-form-control'
/>
</div>
<textarea
placeholder='Your comment'
required
value={review.Body}
onChange={(e) => setReview({ ...review, Body: e.target.value })}
className='wpcf7-form-control'
/>
<button type='submit' className='submit wpcf7-form-control wpcf7-submit' onClick={createReview}>
submit
</button>
</div>
</form>
</div>
<div className='themesflat-spacer clearfix' data-desktop={80} data-mobile={60} data-smobile={60} />
</div>
);
}
export default Ratings;

strapi and react form not adding data to the admin

previous issue
building a rating app using strapi and react throws errors is solved.
But, the records are not getting added to the admin.
can anyone help on this?
This is the code to add and read reviews from strapi admin,
function App() {
const stars = Array(5).fill(0);
const [currentValue, setCurrentValue] = React.useState(0);
const [hoverValue, setHoverValue] = React.useState(undefined);
const handleClick = (value) => {
setCurrentValue(value);
};
const handleMouseOver = (value) => {
setHoverValue(value);
};
const [review, setReview] = useState({});
const [reviews, setReviews] = useState([]);
useEffect(() => {
const fetchData = async () => {
const result = await api.readReviews();
//console.log(result.data);
setReviews(result.data.data);
};
fetchData();
}, []);
const createReview = async () => {
try {
//console.log(review);
const data = await api.createReview(review);
setReview([...reviews, data]);
} catch (error) {
//console.log(error);
}
};
let [reviewCount, setreviewCount] = useState([]);
const setCountFxn = (no) => {
setReview(no);
};
return (
<>
<form>
<div style={styles.container}>
<h2>RATE OUR SERVICE</h2>
<div style={styles.stars}>
{stars.map((_, index) => {
return (
<FaStar
key={index}
size={24}
style={{
marginRight: 10,
cursor: 'pointer',
}}
color={(hoverValue || currentValue) > index ? colors.orange : colors.grey}
onClick={() => {
setReview({ ...review, Rating: index + 1 });
}}
onMouseOver={() => handleMouseOver(index + 1)}
/>
);
})}
</div>
<div>
<input
type='text'
placeholder='input your name'
required
style={styles.input}
value={review.Name}
onChange={(e) => setReview({ ...review, Name: e.target.value })}
/>
</div>
<textarea
placeholder="what's your feedback"
required
style={styles.textarea}
value={review.review}
onChange={(e) => setReview({ ...review, review: e.target.value })}
/>
<button type='submit' style={styles.button} className='btn btn-primary' onClick={createReview}>
submit
</button>
</div>
</form>
<section id='reviews'>
<div className='reviews-heading'>
<span>REVIEWS FROM CUSTOMERS</span>
</div>
<div className='container'>
<div className='row'>
{reviews.map((review, i) => (
<div key={review.id} className='col-md-6'>
<div className='reviews-box'>
<div className='box-top'>
<div className='profile'>
<div className='name-user'>
<strong>{review.attributes.Title}</strong>
</div>
</div>
<div style={styles.stars}>
{Array.from({ length: review.attributes.Rating }).map((i) => (
<FaStar key={i} size={18} color={colors.orange} />
))}
</div>
</div>
<div className='client-comment'>{review.attributes.Body}</div>
</div>
</div>
))}
</div>
</div>
</section>
</>
);
}
export default App;
The form gets submitted and reloads after submit, but the record does not get added to strapi admin. I've set the roles of the data to public.
thanks
Nabi
You need a very specific structure to create a new entry with strapi. I assume your payload looks like this:
{
name: 'xyz',
rating: 5
}
Correct would be:
{
data: {
name: 'xyz',
rating: 5
}
}
Strapi Docs - Creating an entry
Ive figured it out!
The values of the form were named wrong. "Name" should be "Title" and "review" should be "Body". It now adds the data to the strapi admin.

Submit and close modal window. React React-Hook-Form Typescript

I want to submit and close with the button "save". change type to "button" type="submit" value="submit" onClick={ onClose } don't submit and don't close. I am using onClose for close the modal
import { useAppDispatch } from '../redux/hooks';
import { userInfo } from '../redux/model';
import { useForm } from 'react-hook-form';
import { ModalProps } from '../redux/model';
import { setList } from '../redux/slice';
type UI = userInfo;
const AddData: React.FC<ModalProps> = ({ isOpen, onClose }) => {
const [ page, setPage ] = useState(0);
const FormTitles = ["Invoice Address", "Bank Data", "Contact"];
const dispatch = useAppDispatch();
const { register, handleSubmit, formState: { errors, isValid }} = useForm<UI>({ mode: "all" });
const onSubmit = handleSubmit((data) => {
dispatch(setList(data));
});
return isOpen ? (<div className="viewModal">
<div className='modalContent'>
<form onSubmit={ onSubmit }>
<div className="contentForm">
<div className="closeX" onClick={ onClose }>x</div>
<div className="labels">
<div className="titleTxt">{ FormTitles[page] }</div>
{ page === 0 && (<>
<div className="labelInput">
<label htmlFor="additional">Additional</label>
<input { ...register("additional")} id="additional" />
</div>
<div className="labelInput">
... // content
</div>
<div className="labelInput">
... // content
</div>
</>)}
{ page === 1 && (<>
<div className="labelInput">
<label htmlFor="iban">IBAN</label>
<div className="dirCol">
<input { ...register("iban", { required: true, maxLength: 30 })} id="iban" />
<div className="required">{ errors.iban && "This is required!" }</div>
</div>
</div>
<div className="labelInput">
... // content
</div>
{ page === 2 && (<>
{/* *** fax *** */}
<div className="labelInput">
<label htmlFor="fax">Fax</label>
<input { ...register("fax")} id="fax" />
</div>
<div className="labelInput">
... // content
</div>
<div className="labelInput">
... // content
</div>
</div>
<div className="labelButton">
<button className="button2" onClick={ onClose }>Cancel</button>
{ page !== 0 && (<div className="button2 textCancel" onClick={() => { setPage((x) => x - 1)}}
>Previous</div>)}
{ page !== 2 && (<button className="button1" type="button" disabled={ !isValid } onClick={() => { setPage((x) => x + 1)}}
>Next</button>)}
{ page === 2 && (<>
<button className="button1" type="submit" value="submit" onClick={ onClose }>Save</button>
</>)}
</div>
</div>
</form>
</div>
</div>) : null
};
export default AddData;
here AddData off and on, onClose working with cancel and x button
import { useState } from 'react';
import AddData from './AddData';
import { useAppDispatch, useAppSelector } from '../redux/hooks';
import { removeList } from '../redux/slice';
const ListTable = () => {
const [ isModalOpen, setIsModalOpen ] = useState(false);
const toogleModal = () =>setIsModalOpen(!isModalOpen);
const dispatch = useAppDispatch();
const selector = useAppSelector((state) => state.users.list );
return <>
<AddData isOpen={ isModalOpen } onClose={ toogleModal }>
</AddData>
<nav>
<button onClick={ toogleModal }>Add</button>
</nav>
<div className='content'>
... // content
</div>
</>
};
export default ListTable;
Inside of the onClick for your save button you can call onSubmit and onClose.
import { useAppDispatch } from "../redux/hooks";
import { userInfo } from "../redux/model";
import { useForm } from "react-hook-form";
import { ModalProps } from "../redux/model";
import { setList } from "../redux/slice";
type UI = userInfo;
const AddData: React.FC<ModalProps> = ({ isOpen, onClose }) => {
const [page, setPage] = useState(0);
const FormTitles = ["Invoice Address", "Bank Data", "Contact"];
const dispatch = useAppDispatch();
const {
register,
handleSubmit,
formState: { errors, isValid },
} = useForm<UI>({ mode: "all" });
const onSubmit = handleSubmit((data) => {
dispatch(setList(data));
});
return isOpen ? (
<div className="viewModal">
<div className="modalContent">
<form onSubmit={onSubmit}>
<div className="contentForm">
<div className="closeX" onClick={onClose}>
x
</div>
<div className="labels">
<div className="titleTxt">{FormTitles[page]}</div>
{page === 0 && (
<>
<div className="labelInput">
<label htmlFor="additional">Additional</label>
<input {...register("additional")} id="additional" />
</div>
<div className="labelInput">{/* ... // content */}</div>
<div className="labelInput">{/* ... // content */}</div>
</>
)}
{page === 1 && (
<>
<div className="labelInput">
<label htmlFor="iban">IBAN</label>
<div className="dirCol">
<input
{...register("iban", { required: true, maxLength: 30 })}
id="iban"
/>
<div className="required">
{errors.iban && "This is required!"}
</div>
</div>
</div>
<div className="labelInput">... // content</div>
</>
)}
{page === 2 && (
<>
{/* *** fax *** */}
<div className="labelInput">
<label htmlFor="fax">Fax</label>
<input {...register("fax")} id="fax" />
</div>
<div className="labelInput">{/* ... // content */}</div>
<div className="labelInput">{/* ... // content */}</div>
</>
)}
</div>
<div className="labelButton">
<button className="button2" onClick={onClose}>
Cancel
</button>
{page !== 0 && (
<div
className="button2 textCancel"
onClick={() => {
setPage((x) => x - 1);
}}
>
Previous
</div>
)}
{page !== 2 && (
<button
className="button1"
type="button"
disabled={!isValid}
onClick={() => {
setPage((x) => x + 1);
}}
>
Next
</button>
)}
{page === 2 && (
<>
<button
className="button1"
type="submit"
value="submit"
onClick={() => {
onSubmit();
onClose;
}}
>
Save
</button>
</>
)}
</div>
</div>
</form>
</div>
</div>
) : null;
};
export default AddData;

How to retain checked value when filtering list

I have a filtering function 'filterUsers' working on the 'filteredUsers' array of objects. Each object is rendered as a list item with some data and a checkbox. The function is fired every time the user changes the text input value. If an item is checked when filtered out the checked value is lost. I need a solution to retain the checked value.
const UsersList = () => {
const { users } = useContext(UsersContext);
const [checkedUsersIds, setCheckedUsersIds] = useState([]);
const [filteredUsers, setFilteredUsers] = useState([]);
useEffect(() => setFilteredUsers(users), [users]);
useEffect(() => console.log(checkedUsersIds), [checkedUsersIds]);
const checkUsers = async e => {
if (e.target.checked) {
const checkedUser = users.find(user => user.id === Number(e.target.name));
setCheckedUsersIds([...checkedUsersIds, checkedUser.id]);
} else {
setCheckedUsersIds(checkedUsersIds.filter(user => user !== Number(e.target.name)));
}
};
const filterUsers = e => {
setFilteredUsers(
users.filter(
user =>
user.first_name.toLowerCase().includes(e.target.value.toLowerCase().trim()) ||
user.last_name.toLowerCase().includes(e.target.value.toLowerCase().trim())
)
);
};
return (
<>
<input
type="text"
name="filter_users"
className={classes.filter_input}
onChange={e => filterUsers(e)}
placeholder="search user..."
autoComplete="off"
/>
<ul>
{filteredUsers.length ? (
filteredUsers.map(user => {
return (
<label key={user.id} htmlFor={user.name}>
<li className={classes.user_container}>
<div className={classes.user_subcontainer}>
<div
className={`${classes.avatar_container} ${
user.gender === 'Male' ? classes.male : classes.female
}`}
>
{user.avatar ? (
<img className={classes.avatar} src={user.avatar} alt="#" />
) : (
<div className={classes.img_alt}>
{user.first_name.slice(0, 1)}
{user.last_name.slice(0, 1)}
</div>
)}
</div>
<h3
className={user.gender === 'Male' ? classes.male_text : classes.female_text}
>
{user.first_name} {user.last_name}
</h3>
</div>
<div className={classes.checkbox_container}>
<input type="checkbox" name={user.id} onChange={e => checkUsers(e)} />
</div>
</li>
</label>
);
})
) : (
<h1 className={classes.list_loading}>List loading...</h1>
)}
</ul>
</>
);
};
I mucked about with some of the details of your code here, but hopefully it demonstrates how you could use the checked attribute:
const UsersList = ({ users }) => {
const [checkedUsersIds, setCheckedUsersIds] = React.useState([]);
const [filteredUsers, setFilteredUsers] = React.useState([]);
React.useEffect(() => setFilteredUsers(users), [users]);
// React.useEffect(() => console.log(checkedUsersIds), [checkedUsersIds]);
const checkUsers = e => {
if (e.target.checked) {
const checkedUser = users.find(user => user.id === Number(e.target.name));
setCheckedUsersIds([...checkedUsersIds, checkedUser.id]);
} else {
setCheckedUsersIds(checkedUsersIds.filter(user => user !== Number(e.target.name)));
}
};
const filterUsers = e => {
const value = e.target.value.toLowerCase().trim();
setFilteredUsers(
users.filter(
user =>
user.first_name.toLowerCase().includes(value) ||
user.last_name.toLowerCase().includes(value)
)
);
};
return (
<React.Fragment>
<input
type="text"
name="filter_users"
onChange={e => filterUsers(e)}
placeholder="search user..."
autoComplete="off"
/>
<ul>
{ filteredUsers.map(user => {
return (
<li key={user.id}>
<label htmlFor={user.name}>
{user.first_name} {user.last_name}
<input
type="checkbox"
name={user.id}
onChange={e => checkUsers(e)}
checked={checkedUsersIds.includes(user.id)}
/>
</label>
</li>
);
})
}
</ul>
</React.Fragment>
);
};
const App = () =>
<UsersList
users={[
{ id: 1, first_name: 'Harry', last_name: 'Bibbleson' },
{ id: 2, first_name: 'Sally', last_name: 'Refsted' },
{ id: 3, first_name: 'Swonky', last_name: 'Trevor' },
]}
/>;
ReactDOM.render(<App />, document.getElementById('root'));
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>

Resources