React Native 性能缓慢
React Native performance slow
我是 React Native 的新手,我创建了一个自定义的 Instagram 克隆,但是有一些问题。
FlatList 重新渲染很慢。
按下赞按钮后,FlatList 需要 2 秒才能重新呈现。所以我尝试了 Flipkart 的 RecyclerView 包,这也需要 400-600 毫秒。我已经知道 Instagram 和 Facebook 是在 React Native 上构建的,但他们并没有花这么多时间。我想我的代码有问题。
我从 here
获得了 Recycler View 包
重新渲染很慢。
在那些没有任何List的屏幕中,也存在重新渲染缓慢的问题。
Material 顶部标签导航很慢。
我发现 React Navigations's
Material 顶部导航在滑动时工作得非常好,但在单击按钮时,它需要 2-4 秒。
这是我的提要页面代码。
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>
);
}
iOS 和 Web 也有滞后,但可以接受。
I know, I've done very wrong with AsyncStorage, please tell me a short way to do that too.
提前致谢。
在你的情况下,我不知道你为什么要使用另一个包,而 react-native 包含一个名为 FlatList 的内置组件,它由虚拟渲染支持。
进行此更改
rowRenderer={() => ListItem()}
renderFooter={() => footerComp()}
检查 () =>
箭头函数,这将在初始渲染时仅分配一次方法。您需要提供一个 https://reactnative.dev/docs/flatlist#keyextractor
道具来为所有渲染的项目创建一个唯一的 ID(当您想要执行一些操作,如删除元素或更新时将使用)。
通过这个简单的更改,您应该会看到初始渲染和每次重新渲染的大量性能改进。
对接受函数作为参数的道具做同样的事情。
IDK 为什么要将值存储在异步存储上,它们应该存储在本地变量中,例如 useState
挂钩。如果您经常 API 调用或每次重新渲染,请密切注意 API 调用,这肯定会降低应用程序性能。
我的意见
默认情况下,React 和 React Native 很快,但开发人员使用了很多反模式代码,使应用程序变慢并抱怨 RN 很慢。
在这里您可以找到一些在 React Native 中导致性能问题的常见问题。
我是 React Native 的新手,我创建了一个自定义的 Instagram 克隆,但是有一些问题。
FlatList 重新渲染很慢。
按下赞按钮后,FlatList 需要 2 秒才能重新呈现。所以我尝试了 Flipkart 的 RecyclerView 包,这也需要 400-600 毫秒。我已经知道 Instagram 和 Facebook 是在 React Native 上构建的,但他们并没有花这么多时间。我想我的代码有问题。
我从 here
获得了 Recycler View 包重新渲染很慢。
在那些没有任何List的屏幕中,也存在重新渲染缓慢的问题。
Material 顶部标签导航很慢。
我发现 React Navigations's
Material 顶部导航在滑动时工作得非常好,但在单击按钮时,它需要 2-4 秒。
这是我的提要页面代码。
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>
);
}
iOS 和 Web 也有滞后,但可以接受。
I know, I've done very wrong with AsyncStorage, please tell me a short way to do that too.
提前致谢。
在你的情况下,我不知道你为什么要使用另一个包,而 react-native 包含一个名为 FlatList 的内置组件,它由虚拟渲染支持。
进行此更改
rowRenderer={() => ListItem()}
renderFooter={() => footerComp()}
检查 () =>
箭头函数,这将在初始渲染时仅分配一次方法。您需要提供一个 https://reactnative.dev/docs/flatlist#keyextractor
道具来为所有渲染的项目创建一个唯一的 ID(当您想要执行一些操作,如删除元素或更新时将使用)。
通过这个简单的更改,您应该会看到初始渲染和每次重新渲染的大量性能改进。
对接受函数作为参数的道具做同样的事情。
IDK 为什么要将值存储在异步存储上,它们应该存储在本地变量中,例如 useState
挂钩。如果您经常 API 调用或每次重新渲染,请密切注意 API 调用,这肯定会降低应用程序性能。
我的意见
默认情况下,React 和 React Native 很快,但开发人员使用了很多反模式代码,使应用程序变慢并抱怨 RN 很慢。
在这里您可以找到一些在 React Native 中导致性能问题的常见问题。