Is there a way to prevent automatic re-rendering when causing an event within a SectionList?

Is there a way to prevent automatic re-rendering when causing an event within a SectionList?

Problem Description:

This is my return function which contains all components in the renderer. Every time I press on the footerComponent in the Sectionlist, the whole screen re-renders and causes an auto-scroll to position 0.

return (
    <SafeAreaView style={styles.container}>
      <ImageBackground
        source={require("../assets/stars.gif")}
        style={{
          width: Dim.width,
          height: Dim.height,
        }}
        resizeMode="repeat"
      >
        {files ? <List /> : null}
        <CustomModal
          visible={visible}
          onPressIn={() => startRecording()}
          onPressOut={() => stopRecording()}
          onExitPress={() => setVisible(false)}
          onConfirm={() => sendToStorage(ID, len)}
          disabled={!strgUri}
          onDismiss={() => setRecording(null)}
          modalButton={[
            styles.modal,
            pressed
              ? { backgroundColor: Colors.clay }
              : { backgroundColor: Colors.aegean },
          ]}
          progress={progress}
          loadingVisible={sending}
        />
      </ImageBackground>
    </SafeAreaView>
  );

and this is my Animated SectionList component.

const NewSectionList = Animated.createAnimatedComponent(SectionList);
  const List = React.forwardRef((ref, props) => {
    const respondRef = useRef();
    const scrollRef = useRef().current;

    function scrollToSection() {
      if (respondRef.current) {
        respondRef.current.measure((x, y, width, height, px, py) => {
          console.log("height: ", height);
          console.log("y: ", y);
          setHeight(py);
        });

        console.log("scrolling to: ", height);
        if (height != 0) {
          setTimeout(() => {
            console.log("wait height: ", height);
            console.log("dim height: ", Dim.height);

            console.log("1 height: ", Dim.height - height + Dim.height);

            scrollRef?.scrollTo({
              x: 0,
              y: Dim.height - height + Dim.height,
              animated: true,
            });
          }, 1000);
        }
      }
    }

    useEffect(() => {
      scrollToSection();
    });

    const yVal = fadeAnim.interpolate({
      inputRange: [0, 1],
      outputRange: [900, 0],
    });

    const animStyle = {
      transform: [
        {
          translateY: yVal,
        },
      ],
    };
return(
<Animated.View style={[animStyle]}>
        <NewSectionList
          ref={scrollRef}
          stickySectionHeadersEnabled={false}
          sections={files}
          keyExtractor={(item) => item.id}
          style={{
            marginLeft: 10,
            marginBottom: 110,
          }}
          renderItem={({ item }) => (
            <View style={styles.cardContainer}>
              <View
                style={{
                  alignSelf: "flex-start",
                  position: "absolute",
                  marginTop: 5,
                }}
              >
                <Text p4 dusk>
                  {new Date(item.timestamp).toDateString()}
                </Text>
              </View>
              <TouchableOpacity
                onPress={() => visitProfile(item.name, item.email)}
              >
                <Text p2 aegean>
                  {item.name}
                </Text>
              </TouchableOpacity>
              <View styles={styles.cardTap}>
                <TouchableNativeFeedback
                  onPress={() => {
                    playFile(item.url, item.id);
                  }}
                >
                  <AntDesign name="stepforward" size={40} color={Colors.led} />
                </TouchableNativeFeedback>
              </View>
            </View>
          )}
          renderSectionHeader={({
            section: {
              information,
              origin,
              userOrigin,
              emailOrigin,
              origID,
              originDate,
            },
          }) => (
            <View style={styles.headerContainer}>
              <View
                style={{
                  alignSelf: "flex-start",
                  position: "absolute",
                  marginTop: 5,
                }}
              >
                <Text p3 led>
                  {new Date(originDate).toDateString()}
                </Text>
              </View>
              <View style={styles.holder}>
                <TouchableOpacity
                  onPress={() => visitProfile(userOrigin, emailOrigin)}
                >
                  <Text h4 night>
                    {userOrigin}
                  </Text>
                </TouchableOpacity>
              </View>
              <View style={styles.outerInfo}>
                <Text p3 dusk style={styles.textInfo}>
                  {information ? information : ""}
                </Text>
              </View>
              <View styles={styles.cardTap}>
                <TouchableNativeFeedback
                  onPress={() => {
                    playFile(origin, origID);
                  }}
                >
                  <AntDesign
                    name="stepforward"
                    size={40}
                    color={Colors.night}
                  />
                </TouchableNativeFeedback>
              </View>
            </View>
          )}
          renderSectionFooter={({ section: { docId, dataLen } }) => (
            <TouchableOpacity
              ref={respondRef}
              style={styles.notPressed}
              onPress={() => {
                setVisible(true);
                scrollToSection();
                setID(docId);
                setLen(dataLen);
              }}
            >
              <Text p2 white>
                add to convo
              </Text>
            </TouchableOpacity>
          )}
          refreshControl={<RefreshControl onRefresh={() => getData()} />}
        />
      </Animated.View>
    );
  });

I tried to implement a scrollTo() method function to the position of the pressed button, but that is more of a hack than a real solution since it will keep re-rendering and scrolling. Also, the modal that I am trying to activate has other stateful components within it, causing more re-renders. Another attempted fix was trying to memo-ize the modal, however the official docs suggest that premature-optimization isn’t not a real solution and will lead to more bugs down the . Thank you.

Solution – 1

Create new useEffect to debug whether files is always changed when your page is rerendered:

console.log('Screen in rerendered');
useEffect(() => {
   console.log('`files` is changed', JSON.stringify(files, undefined, 2));
}, [files]);

The files shouldn’t be changed when you press footerComponent.

You may also want to wrap your <Animated.View></Animated.View> with memo() to prevent rerendering in its own component if the props are still equal.

Solution – 2

Ok so the solution to my problem was actually just to render the CustomModal component within my List component so when i needed to show the modal, I could set state in the List component, rather than sending it to the parent. Sending it to the parent caused a re-render in the children component every time I would set the state to a different value. So in general if you want to prevent a re-render between siblings, just render the state dependent component in the one with state.

Rate this post
We use cookies in order to give you the best possible experience on our website. By continuing to use this site, you agree to our use of cookies.
Accept
Reject