Я пытаюсь использовать Firestore Snapchats для получения изменений в базе данных в реальном времени. Я использую react-native-cli: 2.0.1
и react-native: 0.64.1
.
export const WelcomeScreen = observer(function WelcomeScreen() {
const [listData, setListData] = useState([]);
const onResult = (querySnapshot) => {
const items = []
firestore()
.collection("Test")
.get()
.then((querySnapshot) => {
querySnapshot.forEach(function(doc) {
const tempData = {key: doc.id, data: doc.data}
items.push(tempData);
});
setListData(items)
});
}
const onError = (error) => {
console.error(error);
}
firestore().collection('Test').onSnapshot(onResult, onError);
}
Все работает отлично, пока я не использую setListData для обновления списка данных. Приложение больше не отвечает, и я получаю предупреждающее сообщение каждый раз, когда пытаюсь добавить или удалить данные из базы данных.
Please report: Excessive number of pending callbacks: 501. Some pending callbacks that might have leaked by never being called from native code
Я создаю тупик, устанавливая состояние таким образом?
Во-первых, вы не хотите настраивать прослушиватель моментальных снимков в теле вашего компонента. Это приводит к увеличению числа слушателей, потому что каждый раз, когда вы выполняете рендеринг, вы добавляете новый слушатель, но каждый слушатель приводит к повторному рендерингу и т. д. Поэтому настройте слушатель только один раз в useEffect:
const [listData, setListData] = useState([]);
useEffect(() => {
function onResult(querySnapshot) {
// ...
}
function onError(error) {
console.info(error);
}
const unsubscribe = firestore().collection('Test').onSnapshot(onResult, onError);
return unsubscribe;
}, []);
Кроме того, ваша функция onResult будет вызываться, когда вы получите результат, и все же вы заставляете ее развернуться и немедленно выполнить get
, чтобы повторно запросить данные, которые у нее уже есть. Вместо этого просто используйте предоставленный вам снимок:
function onResult(querySnapshot) {
const items = []
querySnapshot.forEach(function(doc) {
const tempData = {key: doc.id, data: doc.data()}
items.push(tempData);
});
setListData(items);
}
Спасибо, это сработало отлично. Только один вопрос, где возвращается «отписаться»? Где я могу его использовать?
onSnapshot возвращает функцию отмены подписки, которая отключит прослушиватель моментальных снимков. Затем я возвращаю его из useEffect. Когда вы возвращаете функцию из useEffect, это сообщает react, какую логику очистки требует эффект. React вызовет отмену подписки, когда компонент отключится (или когда эффект запустится снова, но этого не произойдет для этого эффекта).
можно ли использовать
useState
вне функционального компонента