Возникли проблемы с возвратом функции в пользовательский хук React - PullRequest
0 голосов
/ 23 сентября 2019

В настоящее время я пытаюсь создать хук useRadioList(), который отслеживает опору isExpanded для всех дочерних элементов в данном компоненте (когда один дочерний элемент переключает isExpanded, другие дочерние элементы не переключаются)

Я сделал это следующим образом:

  1. Настройте начальное состояние, создав список ложных значений такой же длины, как у детей
  2. Отобразите это состояниеisExpanded prop
  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 не отображается у каждого ребенка после первоначального рендеринга.

Ответы [ 2 ]

0 голосов
/ 23 сентября 2019

Код, который манипулирует дочерними элементами, не изменяет исходные дочерние элементы, но создает новый, поэтому следующий код не действует:

   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)
0 голосов
/ 23 сентября 2019

setRadioList должен использоваться следующим образом:

setRadioList(newList)

Оператор Spread разбивает массив и отправляет каждое значение как отдельный параметр, поэтому, например, 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

...