【问题标题】:Redundant piece of code using React hooks使用 React 钩子的冗余代码
【发布时间】:2020-09-28 10:59:28
【问题描述】:

有固定数量的设置决定组件是否应该可见,即:

const restrictions = {
  isLogged: true, // TRUE stands for: check if the condition is met
  hasMoney: true,
  didWinYesterday: false,
}

对于每个restrictions 键,我使用useState 创建了一个状态并使用false 将它们全部初始化,例如:

const [isUserLogged, setIsUserLogged] = useState(false)
const [hasUserMoney, setHasUserMoney] = useState(false)
const [didUserWinYday, setDidUserWinYday] = useState(false)

接下来,我使用useEffect 检查每个条件并相应地更新状态:

useEffect(() => {
 const checkIfUserIsLogged = async () => {
   // calling an API to get boolean
   const isLogged = await API.call()

   setIsUserLogged(isLogged)
 }

  // If the restriction is set to false, ignore checking and set relevant state
  if (!restrictions.isLogged) {
    setIsUserLogged(true)
    return
  }

  checkIfUserIsLogged()
}, [restrictions.isLogged])

最后,我正在检查是否应该渲染实际的组件,或者我应该像这样提前中断:

if (!isUserLogged) return <p>User not logged in.</p>

useEffect 代码和上面的检查一共重复了 3 次。每个重复都在进行不同的 API 调用并更新不同的状态,但整体结构保持不变。 我希望我能做得更干,但不知道如何开始。欢迎任何提示,谢谢!

【问题讨论】:

  • 我认为您有一个逻辑问题,因为您将事物初始化为false - 您不应该将它们初始化为undefined,因为您还不知道服务器状态,这可以是truefalse?

标签: javascript reactjs react-hooks


【解决方案1】:

我会将单个原子重构为自定义 useRestrictionState 原子,在内部处理效果:

const restrictions = {
  isLogged: true, // TRUE stands for: check if the condition is met
  hasMoney: true,
  didWinYesterday: false,
};

function useRestrictionState(restrictionFlag, apiFunc) {
  const [flag, setFlag] = React.useState(undefined);
  useEffect(() => {
    if (!restrictionFlag) {
      setFlag(true);
    } else {
      apiFunc().then((result) => setFlag(result));
    }
  }, [restrictionFlag]);
  return flag;
}

function Component() {
  const isUserLogged = useRestrictionState(restrictions.isLogged, getLoginState);
  const hasUserMoney = useRestrictionState(restrictions.hasMoney, getUserMoney);
  const didUserWinYday = useRestrictionState(restrictions.didWinYesterday, getUserDidWinYesterday);
}

如果您总是需要所有这些,您可以自然地将其包装在另一个自定义挂钩中:

function useUserRestrictionState(restrictions) {
  const isUserLogged = useRestrictionState(restrictions.isLogged, getLoginState);
  const hasUserMoney = useRestrictionState(restrictions.hasMoney, getUserMoney);
  const didUserWinYday = useRestrictionState(restrictions.didWinYesterday, getUserDidWinYesterday);
  return { isUserLogged, hasUserMoney, didUserWinYday };
}

function Component() {
  const { isUserLogged, hasUserMoney, didUserWinYday } = useUserRestrictionState(restrictions);
}

【讨论】:

    【解决方案2】:

    这是我的看法:

    import { useState, useEffect } from 'react'
    
    const useCheck = (condition: boolean, performCheck: () => boolean): boolean => {
      const [isConditionMet, setIsConditionMet] = useState<boolean>(false)
    
      useEffect(() => {
        const check = async () => {
          const isConditionMet = await performCheck()
          setIsConditionMet(isConditionMet)
        }
    
        if (!condition) {
          setIsConditionMet(true)
        }
    
        check()
      }, [condition, performCheck])
    
      return isConditionMet
    }
    
    export default useCheck
    
    

    用法:

    const isUserLogged = useCheck(restrictions.isLogged, () => true) // 2nd parameter should be an API call in my case
    

    【讨论】:

    • 你的答案没有使用performCheck。它存在于useEffect 的依赖列表中,但不在useEffect 回调中使用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多