react hooks setTimeout after setState



我最近想设计带有react钩的输入组件。该组件以0.5秒输入输入后检查验证。

我的代码

const inputField = ({ name, type, hint, inputValue, setInput }) => {
    // if there is default value, set default value to state
    const [value, setValue] = useState(inputValue);
    // all of validation are true for testing
    const validCheck = () => true;
   let timeout;
    const handleChange = e => {
        clearTimeout(timeout);
        const v = e.target.value;
        setValue(v);
        timeout = setTimeout(() => {
            // if valid
            if (validCheck()) {
               // do something...
            }
        }, 500);
    };
    return (
        <SCinputField>
            <input type={type} onChange={handleChange} />
       </SCinputField>
    );
};

不幸的是,它没有起作用,因为超时变量将在setValue之后的每次续订。

我发现React-Hooks提供了一些功能,例如useref来存储变量。

我应该使用它还是不应该在这种情况下使用反应钩?

update

添加使用效果

const inputField = ({ name, type, hint, inputValue, setInput }) => {
    // if there is default value, set default value to state
    const [value, setValue] = useState(inputValue);
    // all of validation are true for testing
    const validCheck = () => true;
   let timeout;
    const handleChange = e => {
        const v = e.target.value;
        setValue(v);
    };
    // handle timeout
    useEffect(() => {
        let timeout;
        if (inputValue !== value) {
            timeout = setTimeout(() => {
                const valid = validCheck(value);
                console.log('fire after a moment');
                setInput({
                    key: name,
                    valid,
                    value
                });
            }, 1000);
        }
        return () => {
            clearTimeout(timeout);
        };
    });

    return (
        <SCinputField>
            <input type={type} onChange={handleChange} />
       </SCinputField>
    );
};

看起来有效,但我不确定这是使用正确的方法。

这就是我的方式:

import React, {useState, useEffect, useRef} from 'react';
function InputField() {
  const [value, setValue] = useState('');       // STATE FOR THE INPUT VALUE
  const timeoutRef = useRef(null);              // REF TO KEEP TRACK OF THE TIMEOUT
  function validate() {                         // VALIDATE FUNCTION
    console.log('Validating after 500ms...');
  }
  useEffect(() => {                             // EFFECT TO RUN AFTER CHANGE IN VALUE
    if (timeoutRef.current !== null) {          // IF THERE'S A RUNNING TIMEOUT
      clearTimeout(timeoutRef.current);         // THEN, CANCEL IT
    }
    timeoutRef.current = setTimeout(()=> {      // SET A TIMEOUT
      timeoutRef.current = null;                // RESET REF TO NULL WHEN IT RUNS
      value !== '' ? validate() : null;         // VALIDATE ANY NON-EMPTY VALUE
    },500);                                     // AFTER 500ms
  },[value]);                                   // RUN EFFECT AFTER CHANGE IN VALUE
  return(                                       // SIMPLE TEXT INPUT
    <input type='text' 
      value={value} 
      onChange={(e) => setValue(e.target.value)}
    />
  );
}

在下面的摘要上工作示例:

function InputField() {
  const [value, setValue] = React.useState('');
  const timeoutRef = React.useRef(null);
  function validate() {
    console.log('Validating after 500ms...');
  }
  React.useEffect(() => {
    if (timeoutRef.current !== null) {
      clearTimeout(timeoutRef.current);
    }
     
    timeoutRef.current = setTimeout(()=> {
      timeoutRef.current = null;
      value !== '' ? validate() : null;
    },500);
  },[value]);
  
  return(
    <input type='text' value={value} onChange={(e) => setValue(e.target.value)}/>
  );
  
}
ReactDOM.render(<InputField/>, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root"/>

您无需保留对渲染之间超时的引用。您只需从useEffect返回函数即可清除:

React.useEffect(() => {
  const timeout = setTimeout(()=> {
    if (value !== '') {
      validate();
    }
  }, 500);
  return () => {
    clearTimeout(timeout);  // this guarantees to run right before the next effect
  }
},[value, validate]);

另外,不要忘记将所有依赖项传递给效果,包括validate函数。

理想情况下,您将value作为参数传递给验证函数: validate(value)-这样,该函数的依赖项较少,甚至可以纯净并在组件外移动。

另外,如果您具有内部依赖项(例如props中的另一个setStateonError回调(,请使用useCallback()挂钩创建validate函数:

const validate = useCallback((value) => {
  // do something with the `value` state
  if ( /* value is NOT valid */ ) {
    onError(); // call the props for an error
  } else {
    onValid();
  }
}, [onError, onValid]); // and any other dependencies your function may use

如果依赖项不变,这将保留相同的函数参考。

您可以移动超时变量 handlechange method。

const inputField = ({ name, type, hint, inputValue, setInput }) => {
// if there is default value, set default value to state
const [value, setValue] = useState(inputValue);
// all of validation are true for testing
const validCheck = () => true;
const handleChange = e => {

    let timeout;
    clearTimeout(timeout);
    const v = e.target.value;
    setValue(v);
    timeout = setTimeout(() => {
        // if valid
        if (validCheck()) {
           // do something...
        }
    }, 500);
};
return (
    <SCinputField>
        <input type={type} onChange={handleChange} />
   </SCinputField>
);

};

相关内容

  • 没有找到相关文章

最新更新