0

i need some understanding in my code. I thought i know how usestate works but now i'm confused about my output.

Please i need help.

My Code:

import React, { useState, useEffect } from 'react';
import {
  SafeAreaView,
  StyleSheet,
  Text,
  Animated,
  View,
  TextInput,
  Button,
  Keyboard,
  ScrollView,
  UIManager,
} from 'react-native';


const TestCustomKeyboard = props => {


  const [inputScrollObj, setInputScrollObj] = useState({
    inputHeight: 10,
    keyBoardHeight: 0,
    scrollContentHeight: 0,
    scrollContentOffsetY: 0
  });

  console.log("A:", inputScrollObj)

  useEffect(() => {
    Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
    Keyboard.addListener("keyboardDidHide", _keyboardDidHide);

    // cleanup function
    return () => {
      Keyboard.removeListener("keyboardDidShow", _keyboardDidShow);
      Keyboard.removeListener("keyboardDidHide", _keyboardDidHide);
    };
  }, []);

  const inputContentSizeChange = (event) => {
    setInputScrollObj({
      ...inputScrollObj,
      inputHeight: event.nativeEvent.contentSize.height,
    });
    console.log("B", inputScrollObj)
    // Why is the Value 10 and not the inputHeight from the event? 
  }

  const _keyboardDidShow = (event) => {
    setInputScrollObj({
      ...inputScrollObj,
      keyBoardHeight: event.endCoordinates.height,
    });
    console.log("C", inputScrollObj)
    // why is here the inputHeight again 10 and not the setted value 19.42...
  };

  const _keyboardDidHide = () => {
    setInputScrollObj({
      ...inputScrollObj,
      keyBoardHeight: 0
    });
    console.log("D", inputScrollObj)
    
  };

  const scroll1 = (event) => {
    console.log(event.nativeEvent.contentOffset.y)
    console.log(event.nativeEvent.contentSize.height)
  }

  console.log("E", inputScrollObj)

  return (
    <SafeAreaView style={styles.container}>
      <View style={styles.contop}>

        <ScrollView
          onScroll={scroll1}
        >
          <Button title="Hallo1" />
          <Button title="Hallo2" />
          <Button title="Hallo3" />
          <Button title="Hallo4" />
          <Button title="Hallo5" />
          <Button title="Hallo6" />
          <Button title="Hallo7" />
          <Button title="Hallo8" />
          <Button title="Hallo9" />
          <Button title="Hallo10" />
          <Button title="Hallo11" />
          <Button title="Hallo12" />
          <Button title="Hallo13" />
          <Button title="Hallo14" />
          <Button title="Hallo15" />
          <Button title="Hallo16" />
          <Button title="Hallo17" />
          <Button title="Hallo18" />
          <Button title="Hallo19" />
          <Button title="Hallo20" />
          <Button title="Hallo21" />
          <Button title="Hallo22" />
        </ScrollView>
      </View>
      <View style={styles.conbottom}>
        <TextInput
          style={{
            height: inputScrollObj.inputHeight,
            paddingHorizontal: 10,
            // paddingVertical: 15,
            backgroundColor: 'yellow'
          }}
          multiline={true}
          onContentSizeChange={inputContentSizeChange}
        />
      </View>

    </SafeAreaView >
  )
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'red',
    justifyContent: 'space-between'
  },

  contop: {
    backgroundColor: 'green',
    flex: 1
  },
  conbottom: {
  },
});

export default TestCustomKeyboard;

This is the output from the console by starting the Project. This View is the First View which is showing up.

A: Object {
  "inputHeight": 10,
  "keyBoardHeight": 0,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}
E Object {
  "inputHeight": 10,
  "keyBoardHeight": 0,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}
B Object {
  "inputHeight": 10,
  "keyBoardHeight": 0,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}
A: Object {
  "inputHeight": 19.428571701049805,
  "keyBoardHeight": 0,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}
E Object {
  "inputHeight": 19.428571701049805,
  "keyBoardHeight": 0,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}

The first question why is in the console.log("B") the inputHeight 10? I mean i set the value to a new height in the function. But then in console.log("A") it assigned to the right value 19.42...

But if i open the keyboard, the inputHeight value is again 10. Why is this happen? This is the output when the keyboard appers.

A: Object {
  "inputHeight": 10,
  "keyBoardHeight": 282.28570556640625,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}
E Object {
  "inputHeight": 10,
  "keyBoardHeight": 282.28570556640625,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}
C Object {
  "inputHeight": 10,
  "keyBoardHeight": 0,
  "scrollContentHeight": 0,
  "scrollContentOffsetY": 0,
}

isherwood
  • 58,414
  • 16
  • 114
  • 157
juri88
  • 71
  • 7

2 Answers2

1

You are seting an object using useState !

It's working in async, it's means when you setInputScrollObj your component will reload with the new state.

It's mean the console.log after will render the old value because it will be called before the update

try to use:

useEffect(() => {
  console.log("useEffect:", inputScrollObj)
}, [inputScrollObj]);
0

I guess it happens cause state changing is asynchronous and console displays old values

Batraz Jioty
  • 276
  • 2
  • 5
  • But why it change the value to 10 again after keyboard appears? – juri88 Oct 16 '20 at 14:25
  • hm... your useEffect seems run only one time and use old references of keyboard callback functions – Batraz Jioty Oct 16 '20 at 14:28
  • And therefore it changes the state? Is this the right behaviour of react? Or do i have an bug in my code? . How can I avoid this using old references? – juri88 Oct 16 '20 at 14:45
  • That is the working mechanism. There's no bug in your code. Check this out: https://stackoverflow.com/questions/36085726/why-is-setstate-in-reactjs-async-instead-of-sync#:~:text=1)%20setState%20actions%20are%20asynchronous,does%20not%20immediately%20mutate%20this.&text=Thus%20the%20setState%20calls%20are,better%20UI%20experience%20and%20performance. – Pratik Adhikari Oct 16 '20 at 15:12
  • @PratikAdhikari okay thank you. one thing. But why is the value set back to 10 after it is updating correct. It happens if the keyboard appears. This is not the normal behavior that the state is changing back to the initialstate. – juri88 Oct 16 '20 at 15:38
  • This might help you!! useEffect(() => { .... .... }, [inputScrollObj]); And, go through this once: https://reactjs.org/docs/hooks-effect.html – Pratik Adhikari Oct 16 '20 at 16:41
  • @PratikAdhikari okay so i have put the dependency on useEffect. But why, i want add the Listener only once why i need calling useEffect after each update on the state? I need the state only to calculate some values. If useEffect calls multiple times it assign the listener every time? or onlye once? because if add the listener multiple times then it maybe cause some performance issues? – juri88 Oct 16 '20 at 17:21