反应本地模式时间延迟和急动动画



我正在尝试构建一个具有左右旋转木马的react原生屏幕,在旋转木马的每个面板中都有一个带有项目列表的垂直平面列表。在平坦的垂直平面列表中,最多有8-10个转盘面板和5-30个项目,因此渲染的项目最多可能有300个,但通常为100个。

我调用API,每隔2-3秒检查服务器上的数据,并使用新数据设置组件中的状态。这目前是有效的,并且子组件中的数据数据会得到更新。

平面列表中的每个项目都是可点击的,这会触发页面中启动的模式弹出窗口。我遇到的问题是模式弹出需要4-5秒才能出现和消除。此外,当模态最终开始消失时,动画会抖动,深色背景层在移除时似乎会闪烁。

我首先尝试了内置模态,还使用了react原生模态包,两者都是相同的。

我已经尝试使用InteractionManager.runAfterInteractions和shouldComponentUpdate(nextOps,nextState(来尝试阻止我的api调用,直到动画完成,或者在我更改isModalVisible状态属性时阻止其重新渲染。

代码如下,如有任何帮助,将不胜感激。

import {
Text,
Button,
StyleSheet,
View,   
FlatList,   
Dimensions,
Image,
Animated,
SafeAreaView,
TouchableHighlight,
InteractionManager,
} from 'react-native';
import React from 'react';
import Title from './Title';
import CarouselMeeting from './CarouselMeeting';
import Modal from 'react-native-modal';
import Carousel from 'react-native-snap-carousel';
class MeetingDisplay extends React.Component {
constructor(props) {
super(props);        
this.state = {
raceList: [],
meetingList: [],
meetingId: props.navigation.state.params.meetingId,
currentIndex: 0,
raceCount: 0,
activeIndex: 0,
isModalVisible: false,
}
this.refreshScreen = this.refreshScreen.bind(this)
}
componentDidMount() {
InteractionManager.runAfterInteractions(() => {
Promise.all([fetch('http://apicallurl?id' + this.state.meetingId), fetch('http://apicallurl?id' + this.state.meetingId)])
.then(([res1, res2]) => {
return Promise.all([res1.json(), res2.json()])
})
.then(([res1, res2]) => {
this.setState({
raceList: res1,
meetingList: res2.Meets,
})
});
this.interval = setInterval(() => this.updateRaceList(), 3000);
});
}
componentDidUpdate(prevProps, prevState) {
InteractionManager.runAfterInteractions(() => {
if (prevState.meetingId !== this.state.meetingId) {
Promise.all([fetch('http://apicallurl?id' + this.state.meetingId), fetch('http://apicallurl?id' + this.state.meetingId)])
.then(([res1, res2]) => {
return Promise.all([res1.json(), res2.json()])
})
.then(([res1, res2]) => {
this.setState({
raceList: res1,
meetingList: res2.Meets,
})
});
}
});
}
async updateRaceList() {
InteractionManager.runAfterInteractions(() => {
fetch('http://apicallurl' + this.state.meetingId)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
raceList: responseJson,
}, function () {
});
})
.catch((error) => {
console.error(error);
});
});
}
toggleModal = () => {
InteractionManager.runAfterInteractions(() => {
this.setState({ isModalVisible: !this.state.isModalVisible });
});
};
shouldComponentUpdate(nextProps, nextState) {
if(this.state.isModalVisible !== nextState.isModalVisible){
this.setState({ isModalVisible: nextState.isModalVisible})
return false;
} else return true;
}
render() {
const peek = 20;
const gutter = peek / 4;
const cardWidth = Dimensions.get('window').width - gutter * 2 - peek * 2;
const contentOffset = (Dimensions.get('window').width - (cardWidth + (gutter * 2))) / 2;
return (
<>
<Title heading={this.state.raceList.VenueName} />                
<SafeAreaView style={{ flex: 1, backgroundColor: 'rebeccapurple', paddingTop: 50, }}>
<View style={{ flex: 1, flexDirection: 'row', justifyContent: 'center', }}>
<Carousel
layout={"default"}
useScrollView
ref={ref => this.Carousel = ref}
data={this.state.raceList.RaceList}
sliderWidth={cardWidth}
itemWidth={cardWidth - gutter * 2 - peek * 2}
onSnapToItem={index => this.setState({ activeIndex: index })}
renderItem={({ item }) => (
<Animated.View style={{
flex: 1,
paddingTop: 20,
width: cardWidth,                                    
margin: gutter,
backgroundColor: 'blue',
justifyContent: 'center',
alignItems: 'center',
}}>
<FlatList
horizontal={false}
showsVerticalScrollIndicator={true}
legacyImplementation={false}
data={item.runner_list}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }, index) =>
<TouchableHighlight style={{ flex: 1, flexDirection: 'row' }} onPress={this.toggleModal} >
<Image style={{ width: 50, height: 50 }} source={{ uri: item.imageurl }} />                                                
</TouchableHighlight>}
>
</FlatList>
</Animated.View>
)}
/>
</View>
</SafeAreaView>
<Modal isVisible={this.state.isModalVisible}
backdropTransitionOutTiming={1}>
<View style={{ flex: 1 }}>
<Text>Hello!</Text>
<Button title="Hide modal" onPress={this.toggleModal} />
</View>
</Modal>
</>
);
}
}
const styles = StyleSheet.create({
centeredView: {
flex: 1,
justifyContent: "center",
alignItems: "center",
marginTop: 22
},
modalView: {
margin: 20,
backgroundColor: "white",
borderRadius: 20,
padding: 35,
alignItems: "center",
shadowColor: "#000",
shadowOffset: {
width: 0,
height: 2
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5
},
openButton: {
backgroundColor: "#F194FF",
borderRadius: 20,
padding: 10,
elevation: 2
},
textStyle: {
color: "white",
fontWeight: "bold",
textAlign: "center"
},
modalText: {
marginBottom: 15,
textAlign: "center"
}
});
export default MeetingDisplay;

尝试1

我有一个想法,这可能是我使用了一个名为"react native snap carousel"的第三方旋转木马库,所以我试图用一个看起来很糟糕的滚动视图来代替它,并在其中渲染我所有的平面列表/项目,但这并没有改善仍然是2-3秒的弹出时间延迟。

尝试2

我发现了一个名为react.pure的组件,它可能会对状态/道具进行浅层比较,并且只有在项目/状态实际发生变化时才会触发重新渲染,这可能意味着动画/ui线程会停止任何导致问题的东西。但没有更好的(在模拟器和设备上(在模式显示之前仍有长时间的停顿

class MeetingDisplay extends React.PureComponent

尝试4

通过在平面列表外放置一个按钮来触发模式,将平面列表从等式中取出。平面列表位于底部转盘下方的页面底部。

....</View>
</SafeAreaView>
<Modal                    
visible={this.state.isModalVisible}
backdropTransitionOutTiming={1}
>
<View style={{ flex: 1 }}>
<Text>Hello!</Text>
<Button title="Hide modal" onPress={this.toggleModal} />
</View>
</Modal>
<Button title="Show modal" onPress={this.toggleModal} />                
</>
);....

这没有带来任何改进或性能。那么,是什么导致了这个问题呢。是间隔导致的组件不断重新渲染吗?因此,必须有一种方法来暂停我错过的组件重新渲染。任何人

我遇到了同样的问题,并通过在模式中添加以下道具来解决

useNativeDriver={true} 

请参考这个对我有帮助的答案,https://stackoverflow.com/a/62020910/10432212

最新更新