1

I'm creating a react-native app using react-navigation 5.

Let's say I have a screen component like this:

import {View, Text} from 'react-native';

function TextScreen({navigation}) {
  const [text, setText] = useState(null);

  useEffect(() => {
    setText('Some text.');
    navigation.addListener('focus', () => {
      console.log('focus');
      console.log(text); // this is always null :/
    });
  }, []);

  return (
    <View>
      <Text>{text || 'No text'}</Text>
    </View>
  );
}

I have no idea why every console.log(text) displays null value on every focus. I expect text to be null only in the first focus but it happens all the time.

But when I changed this component into class component, everything worked as expected:

import {View, Text} from 'react-native';

class TextScreen extends React.Component {
  state = {
    text: null
  }

  componentDidMount() {
    this.setState({text: 'Some text'});
    this.props.navigation.addListener('focus', () => {
      console.log('focus');
      console.log(this.state.text); // this is null only in the first focus
    });
  }

  render() {
    return (
      <View>
        <Text>{this.state.text || 'No text'}</Text>
      </View>
    );
  }
}

Is there something I'm doing wrong in the first version?

erichio
  • 81
  • 1
  • 7

4 Answers4

7

OK, I found the solution using useRef hook: React useState hook event handler using initial state

So in my case should be:

import {View, Text} from 'react-native';

function TextScreen({navigation}) {
  const [text, _setText] = useState(null);
  const textRef = useRef(text);
  const setText = newText => {
    textRef.current = newText;
    _setText(newText);
  };

  useEffect(() => {
    setText('Some text.');
    navigation.addListener('focus', () => {
      console.log('focus');
      console.log(textRef.current);
    });
  }, []);

  return (
    <View>
      <Text>{text || 'No text'}</Text>
    </View>
  );
}
erichio
  • 81
  • 1
  • 7
2

@erichio could you change from useEffect to useFocusEffect.

import { RouteProp, useFocusEffect } from '@react-navigation/native'

function TextScreen({navigation}) {

  ....

  useFocusEffect(() => {
    setText('Some text.');
    navigation.addListener('focus', () => {
      console.log('focus');
      console.log(text); // this is always null :/
    });

    return () => {
      navigation.removeEventListener('focus',() => /* YOUR_LOGIC */);
    };
  }, []);

  ...
}
Sochetra Nov
  • 335
  • 2
  • 7
  • No. The useFocusEffect exists indeed but it doesn't work in this way (you can check documentation). However I could write my own useFocusEffect to fix this. – erichio May 18 '20 at 22:58
0

You can do in this way

  const onFocusScreen = useCallback(event => {

  console.log(text);

  }, []);

  useEffect(() => {
  navigation.addListener('focus', onFocusScreen);

  return () => {
  navigation.removeEventListener('focus', onFocusScreen);
  };
  }, [onFocusScreen]);
Waheed Akhtar
  • 3,110
  • 1
  • 16
  • 30
0

You can do something like this.

import { useFocusEffect } from '@react-navigation/native';

useFocusEffect (
    React.useCallback(() =>
    {
        console.warn ("tabOrderStatus",text)
    }, [text])
);
Qasim Zubair
  • 177
  • 2
  • 3