使用 React 钩子(useEffect 和 useRef)——为什么 ref 在复选框更改时更新?
Using React hooks (useEffect and useRef) - Why ref gets updated on checkbox changes?
这是从真实项目中模拟出来的模型。
单击 撤消 按钮应该将复选框的状态更改为用户更改它们之前的状态。
当我 check/uncheck 一个复选框时,appRef.current
得到更新!为什么?
App.jsx 中的 effect 挂钩只被调用一次,因为它的 dependencies 数组是空的。
当你点击 check/uncheck all 按钮然后尝试更改复选框并点击 undo 按钮时,混乱变得更多,但这次它起作用了! !
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={{ ...appRef }}
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
检查box.jsx
const CheckBox = ({ name, label, ...rest }) => (
<>
<input type='checkbox' id={name} name={name} {...rest} />
{label && <label htmlFor={name}>{label}</label>}
</>
)
export default CheckBox
输出可用 here and codesandbox
在你的代码中没有发现问题,因此我尝试用我自己的解决方案来解决它。我完全改变了一些代码。也许如果你把它的一部分写回你的,你就会发现问题的根源是什么。
这是代码框 link: https://codesandbox.io/s/using-react-hooks-useeffect-useref-1odx68
这是从真实项目中模拟出来的模型。
单击 撤消 按钮应该将复选框的状态更改为用户更改它们之前的状态。
当我 check/uncheck 一个复选框时,appRef.current
得到更新!为什么?
App.jsx 中的 effect 挂钩只被调用一次,因为它的 dependencies 数组是空的。
当你点击 check/uncheck all 按钮然后尝试更改复选框并点击 undo 按钮时,混乱变得更多,但这次它起作用了! !
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={{ ...appRef }}
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
检查box.jsx
const CheckBox = ({ name, label, ...rest }) => (
<>
<input type='checkbox' id={name} name={name} {...rest} />
{label && <label htmlFor={name}>{label}</label>}
</>
)
export default CheckBox
输出可用 here and codesandbox
在你的代码中没有发现问题,因此我尝试用我自己的解决方案来解决它。我完全改变了一些代码。也许如果你把它的一部分写回你的,你就会发现问题的根源是什么。
这是代码框 link: https://codesandbox.io/s/using-react-hooks-useeffect-useref-1odx68