This is a model simulated from a real project.
Clicking undo button should change the state of checkboxes to the state before user changes them.
When I check/uncheck a checkbox, appRef.current
gets updated! why?
the effect hook in App.jsx is only called once because its dependencies array is empty.
Confusion becomes more when you click check/uncheck all button then try to change the checkboxes and hit undo button but this time it works!!!
App.jsx
import { useEffect, useRef, useState } from 'react'
import Box from './box'
const App = () => {
const [claims, setClaims] = useState()
const appRef = useRef()
const crudTrue = { Create: true, Read: true, Update: true, Delete: true }
const crudFalse = { Create: false, Read: false, Update: false, Delete: false }
const defaultClaims = {
resource1: { ...crudFalse },
resource2: { ...crudFalse, Read: true },
resource3: { ...crudFalse, Read: true },
resource4: { ...crudFalse }
}
useEffect(() => {
// this effect should be called once
// appRef should be set once
appRef.current = { ...defaultClaims }
setClaims({ ...defaultClaims })
}, [])
return (
<Box
claims={claims}
// cloning to be extra sure it is not mutated
boxRef=
onChange={setClaims}
crudTrue={crudTrue}
crudFalse={crudFalse}
/>
)
}
export default App
box.jsx
import { createElement, useEffect, useRef } from 'react'
import CheckBox from './checkBox'
const Box = ({ claims, boxRef, onChange, crudTrue, crudFalse }) => {
const checkRef = useRef()
useEffect(() => (checkRef.current = boxRef.current), [boxRef])
const handleChange = ({ currentTarget: checkbox }) => {
const xclaims = { ...claims }
const parts = checkbox.name.split('-')
xclaims[parts[0]][parts[1]] = checkbox.checked
onChange(xclaims)
}
const handleAll = () => {
const xclaims = { ...claims }
let isAnyClaimFalse = Object.keys(xclaims).some((res) =>
Object.keys(xclaims[res]).some((c) => xclaims[res][c] === false)
)
for (let res in xclaims) xclaims[res] = isAnyClaimFalse ? { ...crudTrue } : { ...crudFalse }
onChange(xclaims)
}
const handleUndo = () => onChange(checkRef.current)
const renderChecks = () => {
const children = []
for (let res in claims)
for (let key in claims[res])
children.push(
<>
{key === 'Create' && res}
<CheckBox
key={res + '-' + key}
name={res + '-' + key}
label={key}
checked={claims[res][key]}
onChange={handleChange}
/>
{key === 'Delete' && <br />}
</>
)
return createElement('div', [], ...children)
}
return (
<>
<button onClick={handleUndo}>undo</button>
<button onClick={handleAll}>check/uncheck All</button>
{renderChecks()}
</>
)
}
export default Box
checkbox.jsx
const CheckBox = ({ name, label, ...rest }) => (
<>
<input type='checkbox' id={name} name={name} {...rest} />
{label && <label htmlFor={name}>{label}</label>}
</>
)
export default CheckBox
Aucun commentaire:
Enregistrer un commentaire