繁体   English   中英

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

[英]Having trouble returning function in custom React hook

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

我这样做的方法是:

  1. 通过创建与子项长度相同的错误值列表来设置初始 state
  2. Map这个state给每个孩子的isExpanded道具
  3. 声明并返回一个切换 function 操作初始列表的 state
// 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)

当我调用切换时,我收到以下错误:

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

编辑:

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

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

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

操作孩子的代码,不会改变原来的孩子,而是创建一个新的,所以下面的代码没有效果:

   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)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM