在回调中使用钩子的解决方法

IT技术 reactjs react-hooks
2021-05-04 13:28:22

我在 redux 商店中有一些元素,我正在等待来自 API 的响应或已经收到响应。

我的想法是创建一个钩子,以免在我需要执行此操作的每个组件中重复逻辑。

但是当然我收到了无法在回调中使用钩子的错误

用例是这样的:假设我从 API1 收到字母。对于我从 API1 收到的每封信函,我都必须调用 API2 以获取有关该信函的更多详细信息,因此我想首先检查我是否已经向 API2 提出了这封特定信函的请求,如果没有,做了。

为简化起见,我将省略对 API2 进行调用但响应尚未到达的情况。

这是我的钩子

useDetails = (letter) => {
  const dispatch = useDispatch()
  const { lettersDetails } = useSelector(state => ({
    lettersDetails: state.api2.lettersDetails
  }));

  const [details, setDetails] = useState('')

  useEffect(() => {
    if (letter) {      
      // See of I already have details for this letter 
      const letterDetails = _.find(lettersDetails, function(o) { return o.letter === letter; });
      if (!letterDetails) {
        dispatch(getLetterDetailsAction(letter))        
      } else {
        setDetails(`The place of ${letterDetails.letter} in the alphabet is ${letterDetails.position}`)
      }
    }
  }, [lettersDetails]);

  return details;
}

现在在我的组件中,我从另一个 api api1 接收信件,并用它们创建一个数组

我想做的是对我收到的每封信使用如下钩子,但我不能。有什么替代方案?

export default () => {      
  const { letters } = useSelector(state => ({
    letters: state.api1.letters // this is an array 
  }));
  const [mappedLetters, setMappedLetters] = useState([])


  useEffect(() => {

    setMappedLetters(letters.map(letter => { 
      return {
        letter,
        description: useDetails(letter) // here i want the return value from the hook
      }
    }))    
}, [letters])

问题是这个逻辑需要在多个组件中重复

非常感谢你

1个回答

您可以从自定义钩子返回值的访问器而不是值本身:

// hook
function useDetails() {
  const dispatch = useDispatch()
  const [details, setDetails] = useState('')
  const { lettersDetails } = useSelector( ... )

  return useCallback((letter) => {
    // have access to letter & lettersDetails
    const letterDetails = // ...
    if (!letterDetails)
      dispatch( ... )
    else
      setDetails(letterDetails)
    return details
  }, [lettersDetails])
}

// component
export default () => {
  // ...
  const getLetter = useDetails()
  useEffect(() => {
     const description = getLetter(letter)
     // ...
  }, [letters])
}