2

I am new to React-Native, I have created an Instagram Clone with customisations, but there are some issues.

  • FlatList Re-Renderring is slow.

When the like button is Pressed, FlatList is taking 2 Seconds to re-render. So I tried into Flipkart's RecyclerView Package, that is too taking 400-600 ms. I have came to know that Instagram and Facebook are built at React Native, but they don't take this much time on like. I guess something is wrong in my code.

I got Recycler View package from here

  • Re-Rendering is slow.

In those screens without any List, there is too an issue of slow re-rendering.

  • Material Top Tabs Navigation is slow.

I have found that React Navigations's Material Top navigation is working absolutely fine on swipe, but on button click, it is taking 2-4 Seconds.

Here is my code for feed page.

import React, { useEffect, useState, useRef } from 'react';
import { SafeAreaView, Pressable, AppRegistry, Text, View, Image, TouchableOpacity, StyleSheet, ImageBackground, ActivityIndicator, Platform } from 'react-native';
import { Pranah } from '../pranah/cust';
import { colors } from '../pranah/colors';
import { uni } from '../css/uni';
import axios from 'axios';
import base64 from 'react-native-base64';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { DataProvider, LayoutProvider, RecyclerListView } from 'recyclerlistview';
import { UserHead } from './tminc/userhead';
import { AntDesign, FontAwesome5, Feather } from '@expo/vector-icons';
import { design } from './tminc/design';
import { WebBasedNavigation } from './tminc/widenav'


const style = StyleSheet.create({
    web: {
        width: uni.dev("100%", "100%", "40%"),
        height: uni.dev("100%", "100%", uni.height - 50),
        marginLeft: uni.dev(0, 0, 10 / 100 * uni.width)
    }
});
const postDesign = {
    width: uni.dev(95 / 100 * uni.width, 95 / 100 * uni.width, 35 / 100 * uni.width),
    height: uni.dev(95 / 100 * uni.width, 95 / 100 * uni.width, 35 / 100 * uni.width),
    backgroundColor: "#ededed",
    borderRadius: 10,
}
const iconDynamicSizing = 25;
const iconDesign = StyleSheet.create({
    icon: {
        margin: 10
    }
});
//POST PART IN PARTS
//USER HEAD



function ListHead(txt) {
    return (
        <>
            <Text
                style={{
                    fontSize: 35,
                    fontWeight: "bold",
                    margin: 20
                }}
            >{txt.txt}</Text>
        </>
    )
}
function MediaCont(obj) {
    return (
        <View
            style={design.media}
        >
            <Image
                source={{ uri: obj.url }}
                defaultSource={{ uri: obj.url }}
                style={postDesign}
            />
            <View
                style={design.mediaSnap}
            >
                <Text style={design.mediaCap}>{obj.caption.length > 20 ? `${obj.caption.substring(0, 20)}...` : obj.caption}</Text>
            </View>
        </View>
    );
}
function TextCont(obj) {
    return (
        <View
            style={design.textContParent}
        >
            <View
                style={[postDesign, design.center]}
            >
                <Text
                    style={design.textMain}
                >{obj.caption}</Text>
            </View>
        </View>
    );
}

let layoutProvider = new LayoutProvider(
    index => {
        return index == 0 ? "HEAD" : "NORMAL";
    },
    (type, dim) => {
        switch (type) {
            case "NORMAL":
                dim.height = uni.dev(uni.width + 150, uni.width + 150, 40 / 100 * uni.width + 150);
                dim.width = uni.dev(uni.width, uni.width, 40 / 100 * uni.width);
                break;
            case "HEAD":
                dim.height = 85;
                dim.width = uni.dev(uni.width, uni.width, 40 / 100 * uni.width);
                break;

        }
    }
);

function PostLikes(obj) {
    let post = obj.postId;
    let like = parseInt(obj.like);
    let navigation = obj.screenNav;
    let toprint;
    if (like == 0) {
        toprint = uni.lang("इसे पसंद करने वाले पहले व्यक्ति बनें", "Be first to like this.");
    } else if (like == 1) {
        toprint = uni.lang("एक व्यक्ति द्वारा पसंद किया गया", "Liked by one person");
    } else {
        like = String(like);
        toprint = uni.lang(`${like} लोगो ने पसंद किया`, `${like} likes`);
    }
    return (
        <>
            <TouchableOpacity
                onPress={() => {
                    navigation.push('LikeList', { postId: post });
                }}
            >
                <Text
                    style={{
                        marginLeft: uni.dev(5 / 100 * uni.width, 5 / 100 * uni.width, 4 / 100 * uni.width),
                        fontWeight: "bold",
                        marginTop: 5
                    }}
                >{toprint}</Text>
            </TouchableOpacity>
        </>
    );
}

const headerComp = ({
    title: uni.lang("सबकुछ ||", "Everything."),
    type: "head"
});

export function Feed({ navigation }) {
    const [List, setData] = useState([headerComp]);
    const [FooterConst, setFoot] = useState(true);
    const [start, setStart] = useState(0);
    // navigation.setOptions({ tabBarVisible: false });

    let dataProvider = new DataProvider((r1, r2) => {
        return r1 !== r2;
    }).cloneWithRows(List);


    function fetchMore() {
        AsyncStorage.getItem("mail")
            .then((val) => {
                let mail = val;
                AsyncStorage.getItem("pass")
                    .then((value) => {
                        let pass = value;
                        //   CONNECTING TO SERVER
                        axios({
                            method: 'post',
                            url: uni.bind('feed'),
                            headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                            data: uni.string({
                                mail: mail,
                                pass: base64.encode(pass),
                                start: start
                            })
                        })
                            .then((resp) => {
                                if (resp.status == 200) {
                                    let page = resp.data;
                                    /*
                                        SERVER RETURNS
                                        nomore | followernull | error | invalid | {json data}
                                    */
                                    if (uni.logic(page) === "error") {
                                        uni.Error();
                                    } else if (uni.logic(page) === "followernull" || uni.logic(page) === "nomore") {
                                        //SET FOOTER
                                        setFoot(false);
                                    } else if (uni.logic(page) === "invalid") {
                                        //SIGNOUT
                                        uni.signOut(navigation);
                                    } else {
                                        setStart(start + 20);
                                        setData(
                                            [
                                                ...List,
                                                ...page
                                            ]
                                        );
                                    }
                                } else {
                                    uni.Error();
                                }
                            })
                            .catch((e) => {
                                uni.Error();
                            });

                    })
                    .catch((e) => { uni.signOut(navigation) })
            })
            .catch(() => { uni.signOut(navigation) })
    }


    function PostAction(obj) {
        let index = obj.in;
        function addRemoveLike() {
            let temp = List;
            temp[index].liked = temp[index].liked === "true" ? "false" : "true";
            // console.warn(temp[index]);
            setData([...temp]);

            //SAVING LIKE ON SERVER
            AsyncStorage.getItem("mail")
                .then((val) => {
                    let mail = val;
                    AsyncStorage.getItem("pass")
                        .then((value) => {
                            let pass = value;
                            //   CONNECTING TO SERVER
                            axios({
                                method: 'post',
                                url: uni.bind('like'),
                                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
                                data: uni.string({
                                    mail: mail,
                                    pass: base64.encode(pass),
                                    post: String(obj.id)
                                })
                            })
                                .then((resp) => {
                                    if (resp.status == 200) {
                                        let page = resp.data;
                                        /*
                                            SERVER RETURNS
                                            true | error | invalid
                                        */
                                        if (uni.logic(page) === "error") {
                                            uni.Error();
                                        } else if (uni.logic(page) === "invalid") {
                                            uni.signOut(navigation);
                                        }
                                    } else {
                                        uni.Error();
                                    }
                                })
                                .catch((e) => { uni.Error() });
                        })
                        .catch((e) => { uni.signOut(navigation) })
                })
                .catch(() => { uni.signOut(navigation) })
        }

        return (
            <>
                <View
                    style={design.postActionParent}
                >
                    <TouchableOpacity
                        onPress={() => {
                            // console.warn(likeRef.current);
                            // console.warn(likeRef.current);
                            addRemoveLike();
                        }}
                    ><AntDesign name={obj.liked === "true" ? "heart" : "hearto"} size={iconDynamicSizing} color="black" style={iconDesign.icon} /></TouchableOpacity>
                    <TouchableOpacity onPress={() => {
                        navigation.push('Comment', { postId: obj.id });
                    }}><FontAwesome5 name="comment" size={iconDynamicSizing} color="black" style={iconDesign.icon} /></TouchableOpacity>
                    <TouchableOpacity><Feather name="send" size={iconDynamicSizing} color="black" style={iconDesign.icon} /></TouchableOpacity>
                    <TouchableOpacity><AntDesign name="retweet" size={iconDynamicSizing} color="black" style={iconDesign.icon} /></TouchableOpacity>
                </View>
                <View
                    style={design.underLinePrnt}
                >
                    <View style={design.underline}></View>
                </View>
            </>
        );
    }

    function TextPost(params) {
        let item = params.data;
        let index = params.in;
        return (
            <>
                <UserHead dp={item.dp} name={item.name} user={item.username} />
                <Pressable onLongPress={() => { alert('null') }}><TextCont caption={item.caption} /></Pressable>
                <PostLikes like={item.fav} postId={item.id} screenNav={navigation} />
                <PostAction liked={item.liked} in={index} id={item.id} />
            </>
        );
    }
    function MediaPost(params) {
        let item = params.data;
        let index = params.in;
        return (
            <>
                <UserHead dp={item.dp} name={item.name} user={item.username} />
                <MediaCont url={item.url} caption={item.caption} />
                <PostLikes like={item.fav} postId={item.id} screenNav={navigation} />
                <PostAction liked={item.liked} in={index} id={item.id} />
            </>
        );
    }

    function ListItem(type, data, index) {
        let item = data;
        return item.type === "head" ? <ListHead txt={item.title} /> : item.type === "text" ? <TextPost data={item} in={index} /> : <MediaPost data={item} in={index} />;
    }

    useEffect(function () {
        // let tmp = List.push(json);
        // setData([
        //     ...List,
        //     ...json
        // ]);
        navigation.setOptions({ tabBarVisible: uni.isPC() == true ? false : true })
        fetchMore();
    }, []);

    function footerComp() {
        return FooterConst == true ? (
            <>
                <ActivityIndicator size={"large"} color={colors.primary} />
                <Pranah.br height={20} />
            </>) : (
            <>
                <Text
                    style={{
                        textAlign: "center",
                        width: "100%",
                        fontSize: 20,
                        fontWeight: "bold",
                        paddingBottom: 13
                    }}
                >{uni.lang("सूची का अंत", "End of Posts")}</Text>
            </>
        );
    }

    return (
        <SafeAreaView style={{ flex: 1, backgroundColor: "#FFFFFF" }}>
            <ImageBackground
                style={{
                    width: "100%",
                    height: "100%"
                }}
                source={require('../assets/background_mobile.png')}
            >
                <Pranah.stb />
                <Pranah.pranahHead nav={navigation} />
                <View
                    style={{ width: "100%", height: "100%", flexDirection: "row" }}
                >
                    <View
                        style={style.web}
                    >
                        <RecyclerListView
                            dataProvider={dataProvider}
                            rowRenderer={ListItem}
                            layoutProvider={layoutProvider}
                            extendedState={{ List }}
                            renderFooter={footerComp}
                            onEndReached={fetchMore}
                        />
                    </View>
                    <WebBasedNavigation navigation={navigation} />
                </View>
            </ImageBackground>
        </SafeAreaView>
    );
}

There were lags in iOS and Web too but those were acceptable.

I know, I've done very wrong with AsyncStorage, please tell me a short way to do that too.

Thanks in advance.

0

1 Answer 1

2

In your case, I don't know why you are using another package when react-native contains a built-in component called as FlatList which is backed by virtualised rendering.

Make this changes

rowRenderer={() => ListItem()}
renderFooter={() => footerComp()}

Check the () => arrow function this will assign the method only once on the initial render. You need to provide a https://reactnative.dev/docs/flatlist#keyextractor prop to create a unique ID for all the rendered items (will be used when you want to do some action like remove element or update).

With this simple change, you should see a lot of performance improvement for the initial render & for each re-render.

Do the same for the props that accept a function as a param.

IDK why are you storing the value on async storage they should be store in a local variable like the useState hook. Keep an eye on the API call if you do frequent API calls or on each re-render surely it will reduce the app performnce.

My Opinion

React & React Native are fast by default but developers use a lot of anti-pattern code and make the application slow and complain RN is slow.

Here you can find some of the common things which cause performance issues in react native.

https://reactnative.dev/docs/performance

Sign up to request clarification or add additional context in comments.

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.