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?

0

4 Answers 4

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>
  );
}
Sign up to request clarification or add additional context in comments.

2 Comments

You could check the answer, since it's the only one that works. And thanks for a solution :)
remember remove the listener when the component is unmounted
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 */);
    };
  }, []);

  ...
}

1 Comment

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.
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]);

Comments

0

You can do something like this.

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

useFocusEffect (
    React.useCallback(() =>
    {
        console.warn ("tabOrderStatus",text)
    }, [text])
);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.