React native “rendered more hooks than during the previous render” when not first load

  Kiến thức lập trình

In my React Native (expo) app, I have a firstLoad variable in AsyncStorage to determine whether the welcome screen or home screen is rendered. The app loads the welcome screen followed by the home screen perfectly well when firstLoad isn’t set (meaning it is the first load). However, I get a “Rendered more hooks than during the previous render” error when firstLoad is false and the home screen needs to be rendered directly.

Here’s my App class in App.js:

export default class App extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      isLoading: true,
      showHome: false,
    }
  }

  componentDidMount() {
    AsyncStorage.getItem('firstLoad').then((value) => {
      if (value == null || value == 'true') {
        this.setState({ showHome: false, isLoading: false });
      } else {
        this.setState({ showHome: true, isLoading: false });
      }
    });
  }

  _onContinue = () => {
    AsyncStorage.setItem('firstLoad', 'false').then(() => {
      this.setState({ showHome: true, isLoading: false});
    });
  }

  render() {

    Appearance.addChangeListener(({ colorScheme }) => {
      this.forceUpdate();  
    });

    if (this.state.isLoading) {
      return (
        <View style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
          <ActivityIndicator size="large" color="#037bfc" />
        </View>
      );
    } else if (!this.state.showHome) {
      return (
        <Welcome onContinue={() => this._onContinue()} />
      );
    } else {
      return (
        <RootSiblingParent>
          <ActionSheetProvider>
            <NavigationContainer theme={
              Appearance.getColorScheme() === 'dark' ? DarkTheme : LightTheme
            }>
              <BottomNav />
            </NavigationContainer>
          </ActionSheetProvider>
        </RootSiblingParent>
      );
    }

  }
}

And this is what my code for the Home Screen looks like:

export default function Home({route, navigation}) {

    const [imagesLoaded, setImagesLoaded] = useState(true);
    const [topStory, setTopStory] = useState({}); 
    const [topPost, setTopPost] = useState({});
    const [loading, setLoading] = useState(true);
    const [articles, setArticles] = useState([
        // article stuff here
    ]);

    const [fontsLoaded, fontError] = useFonts({
        'Open-Sans': require('../assets/fonts/Open_Sans/static/OpenSans-Regular.ttf'),
        'Madimi-One': require('../assets/fonts/Madimi_One/MadimiOne-Regular.ttf'),
    });

    const cardTheme = useColorScheme() === 'dark' ? ColorTheme.cardDark : ColorTheme.cardLight;
    const textTheme = useColorScheme() === 'dark' ? ColorTheme.textDark : ColorTheme.textLight;
    const blurhash = '|rF?hV%2WCj[ayj[a|j[az_NaeWBj@ayfRayfQfQM{M|azj[azf6fQfQfQIpWXofj[ayj[j[fQayWCoeoeaya}j[ayfQa{oLj?j[WVj[ayayj[fQoff7azayj[ayj[j[ayofayayayj[fQj[ayayj[ayfjj[j[ayjuayj[';

    if (!fontsLoaded || !imagesLoaded || fontError) {
        return (
            <SafeAreaView style={styles.container}>
                <ActivityIndicator size="large" color="#0000ff" />
            </SafeAreaView>
        );
    }

    const fetchTopStory = async () => {
        try {
            const postRef = ref(db, 'reports');
            const postSnapshot = await get(postRef).then((snapshot) => {
                if (snapshot.exists()) {
                    const posts = snapshot.val();
                    const postKeys = Object.keys(posts);
                    const postsWithImages = postKeys.filter(key => posts[key].images !== undefined);
                    const postsWithoutImages = postKeys.filter(key => posts[key].images === undefined);

                    const topStoryKey = postsWithImages[Math.floor(Math.random() * postsWithImages.length)];
                    const topStory = posts[topStoryKey];

                    const topPostKey = postsWithoutImages[Math.floor(Math.random() * postsWithoutImages.length)];
                    const topPost = posts[topPostKey];

                    setTopStory(topStory);
                    setTopPost(topPost);
                    setLoading(false);
                } else {
                    console.log("No data available");
                }
            });
        } catch (error) {
            console.error(error);
        }
    }


    useEffect(() => {
        fetchTopStory();
    }, []);

    const refresh = () => {
        setLoading(true);
        fetchTopStory();
    }

    return (
        <SafeAreaView style={styles.container}>
            {loading ? (
                <ActivityIndicator size="large" color="#0000ff" />
            ) : (
                <ScrollView 
                    contentContainerStyle={styles.content}
                    refreshControl={
                        <RefreshControl refreshing={loading} onRefresh={() => refresh()} />
                    }
                >
                    // content is shown here
                </ScrollView>
            )}
        </SafeAreaView>
    );
}

Any help is appreciated. Thank you!

LEAVE A COMMENT