简体   繁体   English

React Native useState 同步

[英]React Native useState sync

I have a component TextInput with a state "text", that represents its value.我有一个带有状态“文本”的组件 TextInput,它表示它的值。 Also, I have an other component UsernameTextInput which wraps the TextInput and contains a state "isUsernameAvailable", which indicates if the current value of the text input is allowed to be written in my database.此外,我还有一个其他组件 UsernameTextInput,它包装 TextInput 并包含一个状态“isUsernameAvailable”,它指示是否允许将文本输入的当前值写入我的数据库中。

As useState is async, sometimes when the user types really fast, the isUsernameAvailable which correspond to the typed username is wrong.由于 useState 是异步的,有时当用户输入非常快时,与输入的用户名对应的 isUsernameAvailable 是错误的。 For example, the username "tarantino" is not available, but sometimes, with my current code, it is, because of useState is async and I am not handling it correctly...例如,用户名“tarantino”不可用,但有时,使用我当前的代码,它是,因为 useState 是异步的,我没有正确处理它......

Is there any way to make that sync?有什么办法可以做到同步吗?

Here is my current code:这是我当前的代码:

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 pseudocode文本输入伪代码

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

Writing fast returns diferent values for the username "tarantino":快速写入会为用户名“tarantino”返回不同的值:

tarantino - true |塔伦蒂诺 - 真实 | tarantino - false塔伦蒂诺 - 假

I think that the problem here is that the state of the UsernameInput "isUsernameAvailable" is updated faster than the TextInput state "text", maybe not the error but I suppose it.我认为这里的问题是 UsernameInput "isUsernameAvailable" 的状态比 TextInput 状态 "text" 更新得更快,也许不是错误,但我想是。

Any ideas how to solve my issue?任何想法如何解决我的问题? Thank you.谢谢你。

Have you considered adding a debounce to handle typing really fast and only calling the firebase.isUsernameAvailable endpoint once the user has stopped typing?您是否考虑过添加去抖动以非常快速地处理输入,并且仅在用户停止输入后才调用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);

I can't see it being good practice to await every single keystroke, not to mention the possibility of running into errors such as the one you are experiencing.我认为await每一次击键都不是一个好习惯,更不用说遇到诸如您遇到的错误的可能性。

EDIT:编辑:

Instead of calling the onChange prop in useEffect try this instead.与其在useEffect中调用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}/>
    ...
 }

This way, instead of doing this usernameInputRef.current.getText();这样,而不是这样做usernameInputRef.current.getText(); in your checkUsername method, you can just use the username value that is being passed in as a parameter.在您的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);
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM