在自定义 React 钩子中返回函数时遇到问题



我目前正在尝试创建一个useRadioList()钩子,用于跟踪给定组件中所有子级的isExpanded道具(当一个子项切换isExpanded时,其他子项取消切换(

我这样做的方式是:

  1. 通过创建与子值长度相同的 false 值列表来设置初始状态
  2. 将此状态映射到每个孩子的isExpanded道具
  3. 声明并返回一个切换函数,用于操作初始列表的状态
// useRadioList.jsx
import React, { Children, isValidElement, cloneElement, useState, useEffect } from "react"
export default (children, allowMultiple = true) => {

// 1) Setup initial list 
const [radioList, setRadioList] = useState(Array(children.length).fill(false))
// 2) Map radioList values to component children on initial render, and do so again if radioList changes
useEffect(() => {
Children.map(children, (child, idx) => {
if (!isValidElement(child)) {return}
return cloneElement(child, {isExpanded: radioList[idx]})
})
}, [radioList])

// 3) Declare "toggle()" to modify the list that keeps track of what indexes are active
const toggle = (targetIndex) => {
let newList = radioList.map((item, idx) => {
if (allowMultiple) {
return targetIndex == idx ? !item : item
} else {
return targetIndex == idx ? !item : false
}
})
setRadioList(newList)
}
return toggle
}
// expected:  const toggle = useRadioList(children)

当我调用切换时,出现以下错误:

警告:来自 useState(( 和 useReducer(( 钩子的状态更新 不支持第二个回调参数。执行副作用 渲染后,使用 useEffect(( 在组件主体中声明它。

编辑:

setRadioList(...newList) ----> setRadioList(newList)

不再收到callback错误,现在似乎我无法有效地将状态映射到子项,因为初始渲染后isExpanded道具没有出现在每个子项中。

操作子项的代码,不会改变原来的子项,而是创建新的子项,因此以下代码不起作用:

Children.map(children, (child, idx) => {
if (!isValidElement(child)) {return}
return cloneElement(child, {isExpanded: radioList[idx]})
});

尝试返回新孩子,如下所示:

export default (originalChildren, allowMultiple = true) => {

// 1) Setup initial list 
const [radioList, setRadioList] = useState(Array(originalChildren.length).fill(false))
const [children, setChildren] = useState(originalChildren);
// 2) Map radioList values to component children on initial render, and do so again if radioList changes
useEffect(() => {
setChildren(children => Children.map(children, (child, idx) => {
if (!isValidElement(child)) {return}
return cloneElement(child, {isExpanded: radioList[idx]})
}));
}, [radioList])

// 3) Declare "toggle()" to modify the list that keeps track of what indexes are active
const toggle = useCallback((targetIndex) => {
setRadioList(radioList => radioList.map((item, idx) => {
if (allowMultiple) {
return targetIndex == idx ? !item : item
} else {
return targetIndex == idx ? !item : false
}
}))
}, [allowMultiple])
return { toggle, children }
}
// use like this:  const { toggle, children } = useRadioList(children)

setRadioList必须像这样使用:

setRadioList(newList)

展开运算符拆分数组并将每个值作为单独的参数发送,例如setRadioList(...[1,2,3])会变得setRadioList(1, 2, 3)这当然是不正确的。

见 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax#Spread_in_array_literals

相关内容

  • 没有找到相关文章

最新更新