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

时间:2020-09-02 19:48:31

标签: reactjs react-hooks

我在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 个答案:

答案 0 :(得分:2)

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

// 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])
}