代码之家  ›  专栏  ›  技术社区  ›  bos570

使用嵌套挂钩更新状态

  •  1
  • bos570  · 技术社区  · 7 年前

    我正在尝试找出如何使用嵌套钩子来更新父组件中的状态。我最近了解到钩子基本上遵循相同的setState()异步更新模式,但我正在努力寻找解决这一问题的方法。

    我有3个定制挂钩:
    useValidateContent :用于验证特定表单的自定义挂钩。
    useValidateRuleOne :用于验证特定规则的自定义挂钩。
    useValidateRuleTwo :用于验证其他特定规则的自定义挂钩。

    我想用 使用验证工具 使用验证程序2 在里面 使用验证内容 点击更新parentcomp。现在,只需单击2次,即可显示消息。

    使用嵌套的自定义钩子以便在第一次运行时更新状态的正确方法是什么?

    const { useState } = React;
    
    const useValidateRuleOne = initState => {
        const[valid, setValid] = useState(initState)
        const[errorMsg, setErrorMsg] = useState(null)
        
        
        const validate = () => {
          // For test purposes just set to false
          setValid(false)
          setErrorMsg('There was an error validating rule one')
        }
        
        return [valid, validate, errorMsg]
        
    }
    
    const useValidateRuleTwo = initState => {
        const[valid, setValid] = useState(initState)
        const[errorMsg, setErrorMsg] = useState(null)
        
        
        const validate = () => {
          // For test purposes just set to false
          setValid(false)
          setErrorMsg('There was an error validating rule two')
        }
        
        return [valid, validate, errorMsg]
        
    }
    
    const useValidateContent = initState => {
      const [valid, setValid] = useState(initState);
      const [validOne, validateOne, errorOne ] = useValidateRuleOne(true)
      const [validTwo, validateTwo, errorTwo ] = useValidateRuleTwo(true)
      const [errorMsg, setErrorMsg] = useState("");
    
      const validate = () => {
        validateOne()
        validateTwo()
        
        let errorMsg = ''; 
        if (!validOne) errorMsg += errorOne;
        if (!validTwo) errorMsg += errorTwo;
        
        setErrorMsg(errorMsg)
        if (errorMsg.length > 1) setValid(false)
      }
    
      return [valid, validate, errorMsg];
    };
    
    
    function ParentComp() {
      const [contentIsValid, validate, contentError] = useValidateContent(true);
    
      const initValidate = () => {
        // values before running validate
        validate();
    
      };
    
      return (
        <div>
          <button onClick={initValidate}>initValidate</button>
          contentIsValid: {contentIsValid.toString()}, contentError: {contentError}
        </div>
      );
    }
    
    ReactDOM.render(<ParentComp />, document.getElementById('root')) 
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
    
    <div id="root"></div>
    0 回复  |  直到 7 年前
        1
  •  1
  •   Jameson    7 年前

    根据hooks API,您不应该有条件地或在嵌套函数内部调用hook。 https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

    您的问题的一个解决方案是添加useeffect,它将在指定的依赖项更改时触发。下面是一个工作示例: https://codesandbox.io/s/5zyljjm7o4

        2
  •  -1
  •   Pavel Kratochvil    7 年前

    从验证规则中生成纯函数,并且只在一个地方存储状态。它应该更干净,也更适合测试。 https://codesandbox.io/s/r4v026lxno