reactjs - React Native - 尝试取消订阅侦听器时出错
问题描述
我有一个用作侦听器的 GraphQL 订阅:
this.createPostListener = API.graphql(
graphqlOperation(onCreatePost),
).subscribe({
next: postData => {
const newPost = postData.value.data.onCreatePost;
const prevPosts = this.state.posts.filter(
post => post.id !== newPost.id,
);
const updatedPosts = [newPost, ...prevPosts];
this.setState({posts: updatedPosts});
},
});
在我的componentWillUnmount
方法中:
componentWillUnmount() {
this.createPostListener.unsubscribe();
}
我的问题是,当我navigate
进入页面时,我立即在模拟器中收到此错误:
类型错误:未定义不是对象(评估“this.createPostListener.unsubscribe”)
我不太明白这个错误,因为它发生在我导航到页面时,所以我还没有创建帖子。
编辑:这是整个帖子:
class SoundwavesScreen extends React.Component {
constructor(props) {
super(props);
this.toggleSortTrending = this.toggleSortTrending.bind(this);
this.toggleSortNewest = this.toggleSortNewest.bind(this);
this.toggleSortForYou = this.toggleSortForYou.bind(this);
this.toggleDistance = this.toggleDistance.bind(this);
this.popupBody = React.createRef();
this.postInput = React.createRef();
this.popupBodyBottom = React.createRef();
this.popup = React.createRef();
this.state = {
confirmDiscardPopup: false,
posts: [],
isLoading: true,
latitude: '',
longitude: '',
postContent: '',
postTitle: 'test',
writePostPopup: false,
user: {
posterID: '',
},
distance: this.props.screenProps.distance,
postInputIsFocused: false,
popupIsVisible: false,
};
}
sortByTrending() {
const {posts} = this.state;
let newPostList = posts;
newPostList = posts.sort((a, b) => a.totalUpvotes < b.totalUpvotes);
this.setState({
posts: newPostList,
});
}
sortByNewest() {
const {posts} = this.state;
let newPostList = posts;
newPostList = posts.sort(
(a, b) => new Date(a.createdDate) < new Date(b.createdDate),
);
this.setState({
posts: newPostList,
});
}
sortByForYou() {
const {posts} = this.state;
let newPostList = posts;
newPostList = posts.sort((a, b) => a.totalComments < b.totalComments);
this.setState({
posts: newPostList,
});
}
toggleSortTrending() {
this.sortByTrending();
}
toggleSortNewest() {
this.sortByNewest();
}
toggleSortForYou() {
this.sortByForYou();
}
toggleDistance(item) {
console.log('dis it? ');
console.log(item);
this.setState({distance: item});
}
componentDidMount = async() => {
this.props.navigation.setParams({toggleTrending: this.toggleSortTrending});
this.props.navigation.setParams({toggleNewest: this.toggleSortNewest});
this.props.navigation.setParams({toggleForYou: this.toggleSortForYou});
this.props.navigation.setParams({toggleDistance: this.toggleDistance});
Geolocation.getCurrentPosition(
position => {
var location = JSON.stringify(position);
this.setState({
latitude: position.coords.latitude,
longitude: position.coords.longitude,
});
},
error => console.log('currentLocation ERROR: ' + error),
{enableHighAccuracy: true, timeout: 20000, maximumAge: 1000},
);
await this.getPosts();
this.createSoundwaveListener = API.graphql(
graphqlOperation(onCreateSoundwave),
).subscribe({
next: postData => {
const newPost = postData.value.data.onCreateSoundwave;
const prevPosts = this.state.posts.filter(
post => post.id !== newPost.id,
);
const updatedPosts = [newPost, ...prevPosts];
this.setState({posts: updatedPosts});
},
});
this.deleteSoundwaveListener = API.graphql(
graphqlOperation(onDeleteSoundwave),
).subscribe({
next: postData => {
const deletedPost = postData.value.data.onDeleteSoundwave;
const updatedPosts = this.state.posts.filter(
post => post.id !== deletedPost.id,
);
this.setState({posts: updatedPosts});
},
});
}
componentWillUnmount() {
this.createSoundwaveListener.unsubscribe();
this.deleteSoundwaveListener.unsubscribe();
}
getPosts = async () => {
await API.graphql(graphqlOperation(listSoundwaves))
.then( result => {
this.setState({ posts: result.data.listSoundwaves.items,
isLoading: false, isMounted: false})
})
}
toggleWritePopup() {
this.postInput.current.focus();
this.popup.current.snapTo(1);
this.setState({
writePostPopup: true,
confirmDiscardPopup: false,
});
}
toggleConfirmDiscardPopup() {
this.setState({
writePostPopup: true,
confirmDiscardPopup: true,
});
// this.postInput.current.blur();
}
toggleCancelDiscard() {
this.setState({
writePostPopup: true,
confirmDiscardPopup: false,
});
this.postInput.current.focus();
}
toggleDiscard() {
// this._panel.hide();
this.popup.current.snapTo(0);
this.postInput.current.blur();
this.setState({
writePostPopup: false,
confirmDiscardPopup: false,
postContent: '',
});
this.postInput.current.clear();
}
handlePostInputFocus = () => this.setState({postInputIsFocused: true});
handlePostInputBlur = () => this.setState({postInputIsFocused: false});
showPopup = () => this.setState({popupIsVisible: true});
hidePopup = () => this.setState({popupIsVisible: false});
renderDeletePost = () => {
if (this.state.confirmDiscardPopup === true) {
return (
<View style={styles.popupBackground}>
<View style={styles.popupDelete}>
<Text style={styles.deleteTitle}>
Would you like to discard this post?
</Text>
<View style={styles.deleteButtonsContainer}>
<TouchableOpacity
style={styles.popupCancel}
onPress={() => this.toggleCancelDiscard()}>
<Text style={styles.popupCloseText}>Cancel</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.popupDiscard}
onPress={() => this.toggleDiscard()}>
<Text style={styles.popupPostText}>Discard</Text>
</TouchableOpacity>
</View>
</View>
</View>
);
}
};
renderBottomSheet = () => (
<View style={styles.popup}>
{/* {this.renderDeletePost()} */}
<View style={styles.popupButtonsContainer}>
<TouchableOpacity
style={styles.popupClose}
onPress={() => {
if (this.state.postContent.length > 0) {
this.toggleConfirmDiscardPopup();
} else {
this.toggleDiscard();
}
}}>
<Image source={require('../assets/cancel.png')} />
{/* <Text style={styles.popupCloseText}>Close</Text> */}
</TouchableOpacity>
<TouchableOpacity
style={styles.popupPost}
onPress={() => {
let missingField = '';
if (this.state.postTitle.length === 0) {
missingField += 'title';
}
if (this.state.postContent.length === 0) {
if (missingField.length > 0) {
missingField += ' and ';
}
missingField += 'content';
}
if (missingField.length > 0) {
Alert.alert(
'Post Error',
'Failed to create post!\nEmpty ' + missingField,
[
{
text: 'OK',
},
],
);
} else {
const post = {
id: generateUniqueID(),
approved: true, //false,
content: this.state.postContent,
createdDate: new Date().toISOString(), // get current time
hidden: false, //true, //inverse of approved
latitude: this.state.latitude.toString(),
longitude: this.state.longitude.toString(),
posterID: this.state.user.posterID,
reported: false,
title: this.state.postTitle,
totalUpvotes: 0,
totalComments: 0,
//user: this.state.user, //TODO: update with user data
};
console.log(post);
createPost(post)
.then(data => {
this.toggleDiscard();
console.log('Created post in DB!');
console.log(data);
/*
EXAMPLE JSON ON CREATE
{"data": {"createSoundwave": {"_deleted": null, "_lastChangedAt": 1588561690399, "_version": 1, "approved": true, "comments": [Object], "content": "aaaa", "createdDate": "1588561689985", "hidden": false, "id": "36f9-db00-280c-9b8c-8f0b-5140-b572-19c1", "posterID": "c98b-57f2-3f3b-a19c-8635-c964-e2fc-99ff", "prompt": null, "promptID": null, "reported": false, "title": "aaaa", "totalComments": 0, "totalUpvotes": 0, "user": null}}}
*/
let postID = data.data.createSoundwave.id;
})
.catch(err => {
console.log('Created post in DB failed!');
console.log(err);
Alert.alert(
'Post Failure',
'Failed to create post!\nTry again!',
[
{
text: 'OK',
},
],
);
});
}
}}>
<Image source={require('../assets/sendButton.png')} />
</TouchableOpacity>
</View>
<View style={styles.popupBody} ref={this.popupBody}>
<Image
style={styles.popupProfilePic}
source={require('../assets/default_profile_photo.png')}
/>
<TextInput
placeholder="What's on your mind?"
style={styles.popupContent}
multiline={true}
maxLength={500}
onChangeText={text => this.setState({postContent: text})}
// autoFocus={true}
keyboardAppearance={'default'}
ref={this.postInput}
inputAccessoryViewID={'charCount'}
onFocus={this.handlePostInputFocus}
onBlur={this.handlePostInputBlur}
/>
</View>
<View style={styles.popupBodyBottomPadding} ref={this.popupBodyBottom} />
</View>
);
render() {
if (this.state.isLoading) {
return (
<View>
<ActivityIndicator />
</View>
);
} else {
// console.log('posts: \n');
// console.log(this.state.posts);
let postCards = [];
this.state.posts.forEach(element => {
console.log('on soundwave page, verison: ' + element._version);
postCards.push(
<View key={element.id}>
<Post
hidden={element.hidden}
soundwaveContent={element.content}
soundwaveDate={element.createdDate}
soundwaveID={element.id}
soundwaveLatitude={element.latitude}
soundwaveLongitude={element.longitude}
soundwavePosterID={element.posterID}
soundwaveTitle={element.title}
soundwaveUpvotes={element.totalUpvotes}
soundwaveComments={element.totalComments}
userPosterID={this.state.user.posterID}
_version={element._version}
/>
</View>,
);
});
return (
<View style={styles.container}>
<LinearGradient
colors={['#0E98DC', '#C55DBB', '#A273D8', '#A7ACD2']}
start={{x: 0, y: 0}}
end={{x: 0, y: 1}}
locations={[0.0417, 0.3385, 0.6667, 1]}
style={styles.linearGradient}>
<View style={styles.titleWrapper}>
<View style={styles.buttonRow}>
<Image
style={styles.title}
source={require('../assets/default_profile_photo.png')}
/>
<SoundwavesDrawerButton />
</View>
<Text style={styles.range}>{this.state.distance} miles away</Text>
{/* <Image
style={styles.bar}
source={require('../assets/titleLine.png')}
/> */}
</View>
{postCards.length === 0 && <Text>No posts found nearby.</Text>}
{/* {this.renderWritePost()} */}
{this.renderDeletePost()}
<ScrollView>{postCards}</ScrollView>
<TouchableOpacity
style={styles.write}
onPress={() => this.toggleWritePopup()}>
<Image source={require('../assets/Post.png')} />
</TouchableOpacity>
<InputAccessoryView nativeID={'charCount'}>
<LinearGradient
colors={['#B8A5FE', '#B5B4FF']}
start={{x: 0, y: 0}}
end={{x: 0, y: 1}}
locations={[0.5989, 0.9242]}
style={styles.charCountBar}>
<Text style={styles.charCountBarText}>
{this.state.postContent.length}/500
</Text>
</LinearGradient>
</InputAccessoryView>
<BottomSheet
ref={this.popup}
snapPoints={[0, '110%']}
renderContent={this.renderBottomSheet}
enabledGestureInteraction={false}
/>
</LinearGradient>
</View>
);
}
}
}
这是我导航到此页面的方式: 我有一个功能:
handleOpenURL = event => {
this.navigate(event.url);
};
navigate = url => {
if (routeName === 'Login') {
let currentSession = this.checkIfAuthenticated;
if (currentSession) {
console.log(
'Authenticated and using Login path, heading to Soundwaves...',
);
this.props.navigation.navigate('Soundwaves', {
id,
name: 'testlogin',
distance: 100,
});
} else {
console.log('Error! Not authenticated but using Login path');
}
}
}
解决方案
推荐阅读
- python - 找不到从终端运行的 Python 模块
- ruby-on-rails - 以一种方式加入,但不是另一种
- visual-studio - 无法使用 MSBuild 的 UnZip 任务解压缩包含文件夹的 zip 文件
- cypress - 比较 datetime 函数 cypress
- python - scikit learn Pipeline 是否将 StandardScaler 应用于 y?
- android - Android 架构蓝图 [todo-mvp-dagger] @ActivityScoped, @FragmentScoped
- typescript - 如何在没有框架的情况下使用 Typescript?
- c - 当你只需要 1 位时,充分利用 256 个随机位
- css - Wordpress 网站标题在滚动页面元素后面移动
- java - 复制异步调用 - new Thread() - 更好的方法?