React Native:组件状态中的重复项
React Native: Duplicate items in component state
我在 StackNavigator 中有两个屏幕,一个带有 FlatList,用于显示从 Firestore 检索的数据,另一个用于向数据库添加新数据。通过 navigation.goBack() 从堆栈中的第二个屏幕返回后,新项目应附加到列表中。相反,具有新项目的整个状态被附加到旧状态。数据库数据不包含重复项,刷新后,列表包含正确的元素。
我不知道我是否误解了组件生命周期或查询本身,因此非常感谢您的帮助。
export default class Main extends React.Component {
state = { chatData:[] }
componentDidMount = () => {
// Make call to Cloud Firestore
// for the current user, retrieve the chat document associated with each element in the chats id array
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).onSnapshot((doc) => {
this.setState({chatData: [...this.state.chatData,
{id: element, subject: doc.data().subject, course: doc.data().course}]})
})
});
})
}
添加课程并返回列表屏幕后的状态(重复元素)
设置状态时尝试使用prevState回调函数。像这样:
export default class Main extends React.Component {
state = { chatData:[] }
componentDidMount = () => {
// Make call to Cloud Firestore
// for the current user, retrieve the chat document associated with each element in the chats id array
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).onSnapshot((doc) => {
// We use the parameter of the first argument of setState - prevState
this.setState(prevState => ({chatData: [...prevState.chatData,
{id: element, subject: doc.data().subject, course: doc.data().course}]}))
})
});
})
}
因为你想像累加器一样传播以前存在的状态以及你从 firestore
获得的新数据。如果您使用 this.state
执行此操作,那么您将再次添加它,因为它涉及已在状态中的数据,因此涉及 repeated/duplicated。如果有帮助,请告诉我。
尝试创建一个具有唯一值的新数组并将其分配给 chatData
componentDidMount = () => {
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).onSnapshot((doc) => {
/**
* create a new array with unique values
*/
let newArray = [...this.state.chatData, { id: element, subject: doc.data().subject, course: doc.data().course }]
let uniqueArray = [...new Set(newArray)]
this.setState({
chatData: uniqueArray
})
})
});
})
}
希望对您有所帮助。有疑问欢迎留言。
这是我最终的解决方案。我正在使用 react-navigation addListener 在切换到第一个屏幕时调用 firestore API 并在导航到第二个屏幕时清除状态。我还从 onSnapshot() 切换到 get() 以进行 firestore 调用。
class Main extends React.Component {
state = { currentUser: null, chatData:[]}
componentDidMount = () => {
console.log('A - component did mount')
// definitely works
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
payload => {
console.log('A- focus')
this.readCourseData()
})
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
payload => {
console.log('A- blur')
this.setState({chatData: []})
})
}
componentWillUnmount() {
console.log('A - component will unmount')
this.willFocusSubscription.remove();
this.willBlurSubscription.remove();
// Remove the event listener
}
readCourseData = () => {
// Make call to Cloud Firestore
// for the current user, retrieve the chat document associated with each element in the chats array
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).get().then((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).get().then((doc) => {
let newArray = [...this.state.chatData, { id: element, subject: doc.data().subject, course: doc.data().course }]
let uniqueArray = [...new Set(newArray)]
this.setState({
chatData: uniqueArray
})
})
});
})
}
我在 StackNavigator 中有两个屏幕,一个带有 FlatList,用于显示从 Firestore 检索的数据,另一个用于向数据库添加新数据。通过 navigation.goBack() 从堆栈中的第二个屏幕返回后,新项目应附加到列表中。相反,具有新项目的整个状态被附加到旧状态。数据库数据不包含重复项,刷新后,列表包含正确的元素。
我不知道我是否误解了组件生命周期或查询本身,因此非常感谢您的帮助。
export default class Main extends React.Component {
state = { chatData:[] }
componentDidMount = () => {
// Make call to Cloud Firestore
// for the current user, retrieve the chat document associated with each element in the chats id array
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).onSnapshot((doc) => {
this.setState({chatData: [...this.state.chatData,
{id: element, subject: doc.data().subject, course: doc.data().course}]})
})
});
})
}
添加课程并返回列表屏幕后的状态(重复元素)
设置状态时尝试使用prevState回调函数。像这样:
export default class Main extends React.Component {
state = { chatData:[] }
componentDidMount = () => {
// Make call to Cloud Firestore
// for the current user, retrieve the chat document associated with each element in the chats id array
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).onSnapshot((doc) => {
// We use the parameter of the first argument of setState - prevState
this.setState(prevState => ({chatData: [...prevState.chatData,
{id: element, subject: doc.data().subject, course: doc.data().course}]}))
})
});
})
}
因为你想像累加器一样传播以前存在的状态以及你从 firestore
获得的新数据。如果您使用 this.state
执行此操作,那么您将再次添加它,因为它涉及已在状态中的数据,因此涉及 repeated/duplicated。如果有帮助,请告诉我。
尝试创建一个具有唯一值的新数组并将其分配给 chatData
componentDidMount = () => {
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).onSnapshot((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).onSnapshot((doc) => {
/**
* create a new array with unique values
*/
let newArray = [...this.state.chatData, { id: element, subject: doc.data().subject, course: doc.data().course }]
let uniqueArray = [...new Set(newArray)]
this.setState({
chatData: uniqueArray
})
})
});
})
}
希望对您有所帮助。有疑问欢迎留言。
这是我最终的解决方案。我正在使用 react-navigation addListener 在切换到第一个屏幕时调用 firestore API 并在导航到第二个屏幕时清除状态。我还从 onSnapshot() 切换到 get() 以进行 firestore 调用。
class Main extends React.Component {
state = { currentUser: null, chatData:[]}
componentDidMount = () => {
console.log('A - component did mount')
// definitely works
this.willFocusSubscription = this.props.navigation.addListener(
'willFocus',
payload => {
console.log('A- focus')
this.readCourseData()
})
this.willBlurSubscription = this.props.navigation.addListener(
'willBlur',
payload => {
console.log('A- blur')
this.setState({chatData: []})
})
}
componentWillUnmount() {
console.log('A - component will unmount')
this.willFocusSubscription.remove();
this.willBlurSubscription.remove();
// Remove the event listener
}
readCourseData = () => {
// Make call to Cloud Firestore
// for the current user, retrieve the chat document associated with each element in the chats array
let user = firebase.auth().currentUser;
firestore().collection("users").doc(user.uid).get().then((doc) => {
doc.data().chats.map((element) => {
firestore().collection("chats").doc(element).get().then((doc) => {
let newArray = [...this.state.chatData, { id: element, subject: doc.data().subject, course: doc.data().course }]
let uniqueArray = [...new Set(newArray)]
this.setState({
chatData: uniqueArray
})
})
});
})
}