Here I'm trying to reset selected radio buttons on this list,
however it doesn't work because
I previously change input check from {checked}
to {user.checked}
. Refer from UserListElement.tsx
below
Therefore, I tried the following two methods.
useEffect(() => {
user.checked = false;
}, [isReset, user]);
→ no change.
setChecked
to true
when addedUserIds includes user.userId if (addedUserIds.includes(`${user.userId}`)) {
setChecked(true);
}
→ Unhandled Runtime Error Error: Too many re-renders. React limits the number of renders to prevent an infinite loop.
Any suggestion on how to make this this work?
UserListElement.tsx
export const UserListElement = ({
user,
handleOnMemberClicked,
isReset,
}: {
user: UserEntity;
handleOnMemberClicked: (checked: boolean, userId: string | null) => void;
isReset: boolean;
}) => {
const [checked, setChecked] = useState(user.checked);
const addedUserIds = addedUserList.map((item) => item.userId) || [];
const handleOnChange = (e: ChangeEvent<HTMLInputElement>) => {
const checkedState = e.target.checked;
setChecked(checkedState); //not called
user.checked = checkedState;
handleOnMemberClicked(checkedState, user.userId);
};
useEffect(() => {
setChecked(false);
}, [isReset, user]);
if (addedUserIds.includes(`${user.userId}`)) {
user.checked = true;
// setChecked(true) cause runtime error (infinite loop)
}
return (
<li>
<label className={style.checkboxLabel}>
<input
type="checkbox"
className={style.checkboxCircle}
checked={user.checked}
// checked={checked}
onChange={(e) => handleOnChange(e)}
/>
<span>{user.name}</span>
</label>
</li>
);
};
UserList.tsx
export const UserList = (props: {
showsUserList: boolean;handleClose: () => void;corporationId: string;currentUserId: string;samePerson: boolean;twj: string;
}) => {
const [isReset, setReset] = useState(false);
.......
const resetAll = () => {
setReset(!isReset);
setCount((addedUserList.length = 0));
setAddedUserList([]);
setUserName('');
};
......
return ( <
> < div > xxxxx <
ul className = {
`option-module-list no-list option-module-list-member ${style.personListMember}`
} > {searchedUserList.map((user, i) => (
<UserListElement user = { user }
handleOnMemberClicked = { handleOnMemberClicked }
isReset = { isReset }
key = {i} />
)) }
</ul>
/div>
<a className="is-secondary reservation-popup-filter-reset" onClick={resetAll}>
.....
}
UseAddUserList.tsx
export class UserDetail {
constructor(public userId: string | null, public name: string | null) {}
}
export let addedUserList: UserDetail[] = [];
export let setAddedUserList: Dispatch<SetStateAction<UserDetail[]>>;
export const useAddUserList = (idList: UserDetail[]) => {
[addedUserList, setAddedUserList] = useState(idList);
};
Further Clarification:
Default view
Searched option (showed filtered list)
I use user.checked
because when using only checked, the checked state does not carry on from filtered list view to the full view (ex. when I erase searched word or close the popup).
The real answer to this question is that the state should NOT be held within your component. The state of checkboxes should be held in UsersList
and be passed in as a prop.
export const UserListElement = ({
user,
handleOnMemberClicked,
isChecked
}: {
user: UserEntity;
handleOnMemberClicked: (checked: boolean, userId: string | null) => void;
isChecked: boolean;
}) => {
// no complicated logic in here, just render the checkbox according to the `isChecked` prop, and call the handler when clicked
}
in users list
return searchedUserList.map(user => (
<UserListElement
user={user}
key={user.id}
isChecked={addedUserIds.includes(user.id)} <-- THIS LINE
handleOnMemberClicked={handleOnMemberClicked}
/>
)
You can see that you almost had this figured out because you were doing this in the child:
if (addedUserIds.includes(`${user.userId}`)) {
user.checked = true;
// setChecked(true) cause runtime error (infinite loop)
}
Which indicates to you that the checkdd value is entirely dependent on the state held in the parent, which means there is actually no state to be had in the child.
Also, in React, NEVER mutate things (props or state) like - user.checked = true
- that's a surefire way to leave you with a bug that will cost you a lot of time.
Hopefully this sheds some light