反应本机useState同步

时间:2020-09-15 18:48:35

标签: javascript reactjs react-native asynchronous async-await

我有一个组件TextInput,其状态为“文本”,代表其值。另外,我还有另一个组件UsernameTextInput,它包装TextInput并包含状态“ isUsernameAvailable”,该状态指示是否允许将文本输入的当前值写入我的数据库。

由于useState是异步的,因此有时当用户键入速度很快时,与键入的用户名相对应的isUsernameAvailable是错误的。例如,用户名“ tarantino”不可用,但是有时,在我当前的代码中,是因为useState是async,并且我没有正确处理它。

有什么办法可以使该同步?

这是我当前的代码:

function UsernameInput(props) {    
  const [isUsernameAvailable, setIsUsernameAvailable] = useState(undefined);

  const usernameInputRef = useRef(null);

  const previousValues = useRef(null);

  const checkUsername = async () => {
    const { firebase } = props;

    // Get the username
    const username = usernameInputRef.current.getText();

    
    // Check if the username is valid and available on the database
    const isUsernameAvailable = validateUsername(username) &&
                          (await firebase.isUsernameAvailable(username));

    setIsUsernameAvailable(isUsernameAvailable);
  };

  useEffect(() => {
    // Get the username from the text input
    const username = usernameInputRef.current.getText();

    if (
      previousValues.current?.username !== username &&
      previousValues.current?.isUsernameAvailable !== isUsernameAvailable
    ) {          
        console.log(`${username} - ${isUsernameAvailable}`)
        
        // Update previousValues reference
        previousValues.current = { username, isUsernameAvailable };
    }
  });

  return (
    <TextInput
      ref={usernameInputRef}
      onChange={checkUsername}
    />
  );
}

TextInput伪代码

 TextInput(props, ref) {
    const getTextInput = () => text;

    const [text, setText] = useState(null)
    
    useEffect(() => {
        const { onChange } = props;
        if(text) onChange();   
    }, [text]);  
 
    return <NativeTextInput value={text} onChange={(e) => setText(e.nativeEvent.text)}/>
    ...
 }

快速写入将返回用户名“ tarantino”的不同值:

tarantino-true | tarantino-错误

我认为这里的问题是UsernameInput“ isUsernameAvailable”的状态更新速度比TextInput状态“ text”的更新速度快,也许不是错误,但我想是错误的。

任何想法如何解决我的问题?谢谢。

1 个答案:

答案 0 :(得分:1)

您是否考虑过添加debounce来真正快速地处理键入,并且仅在用户停止键入后才调用firebase.isUsernameAvailable 端点?

const checkUsername = async () => {
    const { firebase } = props;

    // Get the username
    const username = usernameInputRef.current.getText();

    // Check if the username is valid and available on the database
    const isUsernameAvailable = validateUsername(username) && (await firebase.isUsernameAvailable(username));

    setIsUsernameAvailable(isUsernameAvailable);
};

// The debounced function that you call instead of checkUsername
const debouncedCheck = debounce(checkUsername, 500);

我看不出每次击键await都是一种好习惯,更不用说遇到诸如您正在经历的错误之类的错误了。

编辑:

与其在onChange中调用useEffect道具,不如尝试这个。

TextInput(props, ref) {
    const getTextInput = () => text;

    const [text, setText] = useState(null)

    const handleChange = async (value) => {
      const { onChange } = props;
      setText(value);
      await onChange(value);
    }
 
    return <NativeTextInput value={text} onChangeText={handleChange}/>
    ...
 }

通过这种方式,您不必使用usernameInputRef.current.getText();方法中的checkUsername,而可以使用作为参数传递的username值。

const checkUsername = async (username) => {
    const { firebase } = props;

    // Check if the username is valid and available on the database
    const isUsernameAvailable = validateUsername(username) && (await firebase.isUsernameAvailable(username));

    setIsUsernameAvailable(isUsernameAvailable);
};