Tips for efficiently rendering over 200 views in React Native without sacrificing performance

I've been working on a game project using react-native and I'm facing an issue with rendering over 200 views on the Game screen. Each view should have a pressable functionality that, when pressed, will change the background color of the view and update the score in the game context. However, there seems to be a delay whenever I try to press any of the views for the changes to take effect.

Note

My development environment is Expo and I'm testing the game on a real device.

View Component Snippet

import { useEffect, useState, memo } from "react";
import { useContext } from "react";
import { gameContext } from "./gameContext";
import { Pressable, View } from "react-native";

// Code for CheckBoxCom component

export default memo(CheckBoxCom);

Game Screen Component Snippet

import { useContext, useEffect, useState } from "react";
import { StatusBar } from "expo-status-bar";
import { StyleSheet, Text, View, FlatList } from "react-native";
import CheckBox from "./CheckBox";
import { gameContext } from "./gameContext";

// Code for Game screen component

export default function Game({ navigation }) {
  
}

const styles = StyleSheet.create({
  // Styles for textHeader and checkBoxContainer
});

Is there a way to improve the performance so that the view function runs immediately upon pressing it?

Answer №1

One of the main reasons for the slow performance is due to the fact that when a view is clicked, all 200+ CheckBoxCom components are re-rendered unnecessarily. To improve performance, we can work on preventing these unnecessary re-renders.

The issue seems to stem from the gameContext, which consolidates multiple states. Any changes to these states trigger a re-render of all components. The score state, accessed within each CheckBoxCom, plays a key role in triggering re-renders. By modifying the handlePress() function as follows:

const handlePress = () => {
  if (active) return;
  setActive(true);
  setScore(score => score + 1);
};

We can utilize a callback to update the score without needing to retrieve it from the context. This allows us to remove the score from the game context provider, thereby preventing unnecessary re-renders across components even if the score is not explicitly referenced.

It's important to avoid having numerous state variables within a single context. Segmenting them into separate contexts based on different states can help reduce redundant re-renders within the CheckBoxCom components.

Considering that the CheckBoxCom components possess internal state, implementing React.memo() alone may not effectively prevent re-renders triggered by prop changes only.

To optimize and utilize React.memo(), refactoring to lift the active state to the parent component as activeViews, and passing it as a boolean prop alongside

setScore</code instead of via context, can be beneficial. Additionally, wrapping <code>setState
methods with useCallback() may not always be necessary.

This approach leads to CheckBoxCom components devoid of internal states and external dependencies, making them pure components compatible with React.memo().

Answer №2

Implementing pagination using flatlist

For more information: Pagination in flatlist

import React, { Component } from 'react';
{
  View,
  Text,
  TouchableOpacity,
  StyleSheet,
  FlatList,
  Platform,
  ActivityIndicator,
} from 'react-native';

export default class App extends Component {
  constructor() {
    super();
    this.state = {
      loading: true,
      serverData: [],
      fetching_from_server: false,
    };
    this.offset = 0;
  }
 
  componentDidMount() {
    fetch('https://www.doviz.com/api/v1/currencies/all/latest')
      .then(response => response.json())
      .then(responseJson => {
       responseJson = responseJson.slice((this.offset*12),((this.offset+1)*12)-1)
                 console.log("offset : "+this.offset);

         console.log(responseJson.slice((this.offset*12),((this.offset+1)*12)-1));
        this.offset = this.offset + 1;
        
        this.setState({
          serverData: [...this.state.serverData, ...responseJson],
          loading: false,
        });
      })
      .catch(error => {
        console.error(error);
      });
  }
 
  loadMoreData = () => {
    this.setState({ fetching_from_server: true }, () => {
      fetch('https://www.doviz.com/api/v1/currencies/all/latest')
          .then(response => response.json())
          .then(responseJson => {
           responseJson = responseJson.slice((this.offset*12),((this.offset+1)*12)-1)
            console.log("offset Load : "+this.offset);
          console.log(responseJson);
          
            this.offset = this.offset + 1;
            
            this.setState({
              serverData: [...this.state.serverData, ...responseJson],
              fetching_from_server: false,
            });
          })
          .catch(error => {
            console.error(error);
          });
    });
  };

  renderFooter() {
    return (
      <View style={styles.footer}>
        <TouchableOpacity
          activeOpacity={0.9}
          onPress={this.loadMoreData}
          style={styles.loadMoreBtn}>
          <Text style={styles.btnText}>Loading</Text>
          {this.state.fetching_from_server ? (
            <ActivityIndicator color="white" style={{ marginLeft: 8 }} />
          ) : null}
        </TouchableOpacity>
      </View>
    );
  }

  render() {
    return (
      <View style={styles.container}>
        {this.state.loading ? (
          <ActivityIndicator size="large" />
        ) : (
          <FlatList
            style={{ width: '100%' }}
            keyExtractor={(item, index) => index}
            data={this.state.serverData}
            renderItem={({ item, index }) => (
              <View style={styles.item}>
                <Text style={styles.text}>
                  {item.currency}
                  {'.'} 
                  {item.code}
                </Text>
              </View>
            )}
            onEndReached={this.loadMoreData}
            onEndReachedThreshold ={0.1}
            ItemSeparatorComponent={() => <View style={styles.separator} />}
            ListFooterComponent={this.renderFooter.bind(this)}
          />
        )}
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    paddingTop: 30,
  },
  item: {
    padding: 10,height:80
  },
  separator: {
    height: 0.5,
    backgroundColor: 'rgba(0,0,0,0.4)',
  },
  text: {
    fontSize: 15,
    color: 'black',
  },
  footer: {
    padding: 10,
    justifyContent: 'center',
    alignItems: 'center',
    flexDirection: 'row',
  },
  loadMoreBtn: {
    padding: 10,
    backgroundColor: '#800000',
    borderRadius: 4,
    flexDirection: 'row',
    justifyContent: 'center',
    alignItems: 'center',
  },
  btnText: {
    color: 'white',
    fontSize: 15,
    textAlign: 'center',
  },
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can I set a header to be automatically included in every "render" response in Node.js/Express?

One of the challenges I face involves implementing "controllers" in my code: app.get('/',function(req,res){ var stuff = { 'title': 'blah' }; res.render('mytemplate',stuff); }); In particular, I'm worki ...

Creating pathways in AJAX with Rails

Issue at hand: undefined variable article_id. The objective: Setting up the correct route for AJAX and Rails. What I require: The format articles/1/comments/2. Main goal: To specifically load comment through AJAX, not article. In the current AJAX scrip ...

Unable to use console log in shorthand arrow function while working with Typescript

When debugging an arrow function in JavaScript, you can write it like this: const sum = (a, b) => console.log(a, b) || a + b; This code will first log a and b to the console and then return the actual result of the function. However, when using TypeSc ...

Is there a way to include multiple TinyMCE editors with unique configurations for each one?

Is it possible to incorporate multiple TinyMCE editors on a single page, each with its own distinct configuration settings? If so, how can this be achieved? ...

Is there a way to showcase the value of this.state in save.js?

I'm currently exploring React and have a question regarding displaying the values of this.state in my WordPress frontend. Specifically, I am working on save.js. In edit.js: import apiFetch from '@wordpress/api-fetch'; const { Component } = ...

Tips for eliminating fade effect during hover in networkD3 chart in R

Currently, I have been exploring the usage examples of networkd3 in r I am curious if there is a way to eliminate the hover effect where everything else fades when hovering over a specific node in the graph. For reference, check out "Interacting with igra ...

Having trouble with React testing-library: Why is the file upload empty when testing a PDF file?

While testing file upload with react-testing-library, I encountered an issue where the log indicated that the file was empty (even though it worked in the browser). After researching various docs and bugs, I discovered that since tests run on Node.js, the ...

Is it possible to detect inline elements that have been wrapped?

I am facing a challenge with displaying an indefinite amount of in-line elements. Depending on the width of the browser, some elements may shift to a new line. I am curious to know if it is possible to identify and isolate these rows of elements, or if the ...

Unable to save or create files in Store.js

Recently, I've been trying to save a file on client storage using Store.js. After changing the date with store.set and logging it to the console successfully, I encountered an issue where the data was not being saved in the app directory as expected. ...

The dynamic categorization feature in Redux Form

My approach with Redux Form involves dynamically populating the subcategories in a select field based on the category selected by the user. I accomplished this by creating an API for fetching all categories, triggering an action to load these categories in ...

Creating a stunning image carousel in Vue by integrating a photo API: step-by-step guide

Trying to figure out how to create an image carousel in Vue using photos from an API. Currently able to display the photos using: <section class="images"> <img v-for="image in images" :key="image.id":src="image.assets.large.url"> &l ...

Recurrence of solely the middle segment of the separator's background picture

I have a unique divider image with fading top and bottom parts. I'm wondering if it's possible to use a sprite and 3 divs to only repeat the middle section, considering that my height is variable. Do I need separate images for the top, middle, an ...

How can I trigger an event to append a UL element using

Can anyone suggest a more elegant solution for handling an append/remove event from an element without having to manually trigger an event or resorting to other methods? It would be great if there was a way to do something like this: $('#id').o ...

Incorporate a personalized add-button into the material-table interface

My current setup includes a basic material-table structured like this: <MaterialTable options={myOptions} title="MyTitle" columns={state.columns} data={state.data} tableRef={tableRef} // Not functioning properly editabl ...

Selenium htmlUnit with dynamic content failing to render properly

My current project involves creating Selenium tests for a particular website. Essentially, when a user navigates to the site, a CMS injects some dynamic elements (HTML + JS) onto the page. Everything works fine when running tests on the Firefox driver. H ...

Failure of React Library in Production Mode on Webpack 4

Encountering an issue while trying to compile my react library in mode: production. After importing the library into another application, the following error message is displayed: Uncaught TypeError: Cannot set property props of #<TWithProps> which ...

Is there a way to retrieve data from three different Bookshelf.js models in a single query?

Three tables are in my database: User, UserDrink, and VenueDrink Here is a preview of the sample data: User id | name | gender | -------------------- 1 | John | male | 2 | Jane | female | UserDrink id | count | user_id | venue_drink_id 1 | 3 | ...

Warning of superfluous escape character when executing 'npm start' on a React application

I have encountered a warning while running my React app using npm start. The warning appears in the terminal and reads as follows: Line 24: Unnecessary escape character: \[no-useless-escape The warning is related to the following code snippet: va ...

Navigating through various div elements in Javascript and sending parameters to a script

Context In my project, I am using PHP to generate a series of voting sections. Each section follows the same format except for a unique number assigned to it, which increases with each iteration of the PHP loop. To keep track of the unique numbers, I uti ...

Using the Table-multiple-sort feature in boostrap-table is not functioning properly when there are multiple tables present on a single page

I have implemented bootstrap-table along with the extension table-multiple-sort. The issue I am facing is when I include two tables on a single page (with the second table within a modal window), the multisort feature does not seem to work on the second ta ...