Home > Back-end >  How to set a state of a React component based on more than one other states?
How to set a state of a React component based on more than one other states?

Time:08-20

I am working on a screen which has a button to record audio. And depending on the state of the recording I'd like to hide a text input box which is on the same screen. To hide it I am changing the opacity and making it not editable.

I am setting 2 states (isTextInputEditable and textInputOpacity) based on 2 other ones (isRecording and isRecorded). I am having issues with my current code because useState is asynchronous and the state of isRecording and isRecorded are not updated when I perform the checks in setTextInputVisibility function.

Any tips would be helpful, thanks.

    const [isTextInputEditable, setIsTextInputEditable] = useState(true);
    const [textInputOpacity, setTextInputOpacity] = useState(1);
    const [isRecording, setIsRecording] = useState(false);
    const [isRecorded, setIsRecorded] = useState(false);

    const onRecord = () => {
        if (!isRecording) {
            console.log("Started recording audio")
            setIsRecording(true)
            setIsRecorded(false)
        }
        else {
            console.log("Stopped recording audio")
            setIsRecording(false)
            setIsRecorded(true)
        }
        setTextInputVisibility();
    }

    const setTextInputVisibility = () => {
        if (!isRecording && !isRecorded){  
            setIsTextInputEditable(true)
            setTextInputOpacity(1)
            console.log("Text input visible")
        }
        else{
            setIsTextInputEditable(false)
            setTextInputOpacity(0)
            console.log("Text input invisible")
        }
    }

CodePudding user response:

I think your problem is not caused by the asynchronous nature of state, but rather the conflicting conditions:

if (!isRecording && !isRecorded){ ... } // this is the problem

Previously, in the onRecord function, you set isRecording and isRecorded as such:

setIsRecording(true)
setIsRecorded(false)
// or the other way around

This cause !isRecording && !isRecorded never evaluate to true, because, there will always be the case that either one of them to will be false! So isTextInputEditable and textInputOpacity will always be false and 0!

Possible fix:

const setTextInputVisibility = () => {
  if (!isRecording) { // <- only depends on one state condition
    setIsTextInputEditable(true);
    setTextInputOpacity(1);
    console.log("Text input visible");
  } else {
    setIsTextInputEditable(false);
    setTextInputOpacity(0);
    console.log("Text input invisible");
  }
};

Again, as tomleb rightful pointed out in the comment, how to manage state is the real issue here, for instance, you may not need textInputOpacity state at all, since it is basically the same as isTextInputEditable, and they both serves the same purpose.

Check out sandbox.

CodePudding user response:

You don't have to use state for hiding text input since hiding text input is dependent on isRecording and isRecorded

You can do something like this

    const [isRecording, setIsRecording] = useState(false);
    const [isRecorded, setIsRecorded] = useState(false);

    const onRecord = () => {
        if (!isRecording) {
            console.log("Started recording audio")
            setIsRecording(true)
            setIsRecorded(false)
        }
        else {
            console.log("Stopped recording audio")
            setIsRecording(false)
            setIsRecorded(true)
        }
        setTextInputVisibility();
    }

    const isTextInputEditable = !isRecording && !isRecorded
    const textInputOpacity = (!isRecording && !isRecorded) ? 1 : 0


    return (
        <View>

            {/* Your code goes here */}

            <TextInput 
                disabled={!isTextInputEditable}
                style={{ ...styles.inputStyles, opacity : textInputOpacity }}
            />

        </View>
    )
  • Related