NoriginMedia / react-spatial-navigation

DEPRECATED. HOC-based Spatial Navigation. NEW Hooks version is available here: https://github.com/NoriginMedia/norigin-spatial-navigation
MIT License
226 stars 64 forks source link

more than 100 UI elements in funcational component taking too long to navigate. #112

Closed sajjadgrw1 closed 2 years ago

sajjadgrw1 commented 2 years ago

I am using renative for a tizen Application I am using withFocusable() to make UI components focusable like this.

`<FocusableView

        focusKey="submit"
        style={{}}
        onArrowPress={handleUp}
        onBecameFocused={() => {
          console.log('become focused ');
          setInputTextFocusStyleSubmit(LoginStyle.inputTextFocusStyleFocused)
        }}
        onBecameBlurred={()=>{
          setInputTextFocusStyleSubmit(LoginStyle.inputTextFocusStyleNormal)
        }}
        onEnterPress={() => {

          validateForm(navigation);

        }}
      >
        <TouchableHighlight
          ref={submitRef}
          focusKey="submit"
          underlayColor="skyblue"
          style={[LoginStyle.ButtonStyle, inputTextFocusStyleSubmit]}

          onPress={() => {
            console.log('on press ');
            //validateForm(navigation);
          }}

        >
          <Text
            style={[
              { paddingTop: '1%', fontSize: 50 },
              isDarkMode ? { color: 'white' } : null,
            ]}
          >
            ADD THIS TV
          </Text>
        </TouchableHighlight>
      </FocusableView>`

export default withFocusable({ })(LoginView);

when there are less than 10 focusable components on screen it renders fine But my use case is to show gallery images on homescreen functional component. In that case it is taking more or less 10 seconds to navigate to another component.

Was wondering if changing my screen from functional to class component, will that help ? And honestly i can not do that , that will require to restructure the application

This is the only hurdle in completing the application. Thanks in advance.

predikament commented 2 years ago

Hello @sajjadgrw1.

Thanks for getting in touch. I will try to give you some input, albeit I can only offer pointers as I do not have the full overview of what you're trying to achieve and how you're going about it.

In regards to your question:

Was wondering if changing my screen from functional to class component, will that help ? And honestly i can not do that , that will require to restructure the application

No, this would not help address the performance issues you're seeing.

In general I would assume that the problem stems from how your components are working, what is being re-rendered, side-effects and things like that.

As an example, from your snippet above, most of your callbacks are written in a relatively inefficient way:

onBecameFocused={() => {
  console.log('become focused ');
  setInputTextFocusStyleSubmit(LoginStyle.inputTextFocusStyleFocused)
}}
onBecameBlurred={()=>{
  setInputTextFocusStyleSubmit(LoginStyle.inputTextFocusStyleNormal)
}}
onEnterPress={() => {
  validateForm(navigation);
}}

All of these callbacks are recreated every single time the component is rendered. Doing it in this way can be a big performance bottleneck in itself.

When you assign a prop to an anonymous function (() => ..) like you are, this means the address of this function is not stored - Since it is not stored, the engine does not know to reuse the block of memory which the function was occupying, meaning the next time the elements are drawn a new function is created and more memory is taken up. Some of the unused memory will of course be freed up once garbage-collection happens, but that does not address the core issue which is how they were created, which can be changed to alleviate the problem itself.

Optimally you should create and bind these callback functions explicitly (class) or be using something like useCallback (functional).

Here's an example based on your shared snippet :

import React, {useCallback} from 'react';
import FocusableView from './focusable-view';

/* 
  Note: Not sure where LoginStyle and setInputTextFocusStyleSubmit come from, 
  so for this example I will work with the assumption that they're passed in as props.
 */
const LoginView = ({LoginStyle, setInputTextFocusStyleSubmit}) => {
  const onTextFocused = useCallback(() => {
    setInputTextFocusStyleSubmit(LoginStyle.inputTextFocusStyleFocused);
  }, [setInputTextFocusStyleSubmit]);

  const onTextBlurred = useCallback(() => {
    setInputTextFocusStyleSubmit(LoginStyle.inputTextFocusStyleNormal);
  }, [setInputTextFocusStyleSubmit]);

  return (
    <FocusableView
        onBecameFocused={onTextFocused}
        onBecameBlurred={onTextBlurred}
        ..
     />
  );
};

export default withFocusable()(LoginView);

Doing these changes should in themself introduce a huge performance improvement, especially if you have upwards of a hundred components that are all recreating these functions at every single render.

In addition I would look into the following things:

Google is full of of React tutorials related to performance improvements like this, so I would start there.