Я нахожусь в странной ситуации с использованием ловушек React и firebase, в первую очередь Привет, я работаю над нативным приложением React, использующим облачный firestore в качестве моего бэкэнд-сервиса и навигацию по React. Я обрабатываю выборку данных, как известно с помощью useEffect (() => {}, []), но я вызываю мой API в самом дочернем компоненте, поэтому я заметил, что каждый раз, когда мой код отображает его, запускается API-функция, вызывающая чрезвычайно больше операций чтения и пожарного хранилища. это так дешево.
Вот фрагмент кода:
Родитель:
import React, { useState, useEffect } from 'react';
import {View, Text, Dimensions} from 'react-native';
import MyTasksTab from './MyTasksTab';
import TaskInvitationsTab from './TaskInvitationsTab';
import MyApplicationTab from './MyApplicationTab';
import { TabView, SceneMap, TabBar } from 'react-native-tab-view';
import EStyleSheet from 'react-native-extended-stylesheet';
//Get width of mobile screen
var width = Dimensions.get("window").width;
var height = Dimensions.get("window").height;
const TasksMainScreen = (props) => {
const { t, locale } = props.screenProps;
const [index, setIndex] = useState(0);
const [routes, setRoutes] = useState([
{ key: 'first', title: t('tasksMain.myTasksTabTitle') },
{ key: 'second', title: t('tasksMain.taskInvitationTabTitle') },
{ key: 'third', title: t('tasksMain.myApplicationsTabTitle') }
]);
useEffect (() => {
props.navigation.setParams({
styles
});
},
[]);
return (
<View style={styles.container}>
<TabView
navigationState={{index, routes}}
renderScene={SceneMap({
first: () => <MyTasksTab memoProps={memoProps}/>,
second: () => <TaskInvitationsTab {...props}/>,
third: () => <MyApplicationTab {...props}/>
})}
onIndexChange={index => setIndex(index)}
initialLayout={{width}}
renderTabBar={(props) =>
<TabBar
{...props}
activeColor={EStyleSheet.value('$tabNavActive')}
inactiveColor={EStyleSheet.value('$tabNavInactive')}
style={styles.tabView}
labelStyle={textStyles.text15}
indicatorStyle={styles.tabViewIndictor}
/>
}
/>
</View>
);
}
export default TasksMainScreen;
Ребенок:
import React from 'react';
import { View, FlatList, ActivityIndicator } from 'react-native';
import { ApplicantsCard } from '../../../GlobalReusableComponents/SeemCards';
import EmptyTab from '../EmptyTab';
import firebase from '../../../util/firebaseConfig';
import useGetMyTasks from '../../../context/useGetMyTasks';
import dateFromSeconds from '../../../util/dateFromSeconds';
import EStyleSheet from 'react-native-extended-stylesheet';
const MyTasksTab = (props) => {
const {
myTasks,
isFetchMyTasks,
fetchMyTasks
} = useGetMyTasks(firebase.auth().currentUser.uid);
const _keyExtractor = (item, i) => `${item.date}-${i}`;
const _renderApplicantsCard = ({item}) => {
let {date, time} = dateFromSeconds(item.lastDateToApply.seconds);
return (
<View style={styles.cardContainer}>
<ApplicantsCard
date={date}
time={time}
priceText='Est Budget: '
price={item.estimatedBudget}
title={item.name}
description={item.yearsOfExperience}
state={item.city}
onPress={() => props.navigation.navigate('MyTaskDetails', {myTask: item})}
{...item}
/>
</View>
);
}
if(!myTasks){
return (
<View style={{flex: 1, justifyContent: 'center'}}>
<ActivityIndicator color={EStyleSheet.value('$primaryColor')}/>
</View>
);
}
if(myTasks.length == 0){
return (
<EmptyTab
image={require('../../../assets/FindExpert.png')}
details={`You don't have Tasks yet, Create a new Task now.`}
buttonText='Create A New Task'
onButtonPress={() => props.navigation.navigate('AboutTask')}
{...props}
/>
);
}
return (
<View style={styles.container}>
<View style={styles.flatListContainer}>
<FlatList
data={myTasks}
keyExtractor={_keyExtractor}
renderItem={_renderApplicantsCard}
refreshing={isFetchMyTasks}
onRefresh={() => fetchMyTasks()}
/>
</View>
</View>
);
}
export default MyTasksTab;
Крюк для вызова myTasks Firestore Api:
import { useEffect, useState } from 'react';
import firebase from '../util/firebaseConfig';
export default (id) => {
const [myTasks, setMyTasks] = useState(null);
const [isFetchMyTasks, setIsFetchMyTasks] = useState(false);
const fetchMyTasks = () => {
setIsFetchMyTasks(true);
firebase.firestore().collection('tasks').where('user_id', '==', id).orderBy('createdAt', 'desc').get()
.then((querySnapshot) => {
let tasks = [];
querySnapshot.forEach(function(document) {
tasks = [
...tasks,
{
task_id: document.id,
...document.data()
}
]
});
setIsFetchMyTasks(false);
setMyTasks(tasks);
})
.catch((error) => {
setIsFetchMyTasks(false);
})
};
useEffect(() => {
fetchMyTasks();
},
[])
return {
myTasks,
isFetchMyTasks,
fetchMyTasks
};
};
Я искал день, пытаясь выяснить, что происходит, пока я получил тот факт, что useEffect срабатывает один раз при каждом рендеринге, если вы оставляете массив после функции пустым и если я хочу остановить это, я мог бы использовать memo для дочернего компонента и useMemo для запоминания примитивных значений, а useCallback для запоминания массивов и объектов, поэтому я попробовал этот подход с нет никакой надежды, поэтому я пошел с другой идеей, переместив мой хук API в родительский компонент и попытался передать реквизиты его дочернему элементу, чтобы предотвратить чрезмерный вызов API, но мой компонент Flatlist перерисовывается, вызывая прокрутку к началу поведения в каждом новом наборе данных к основному массиву данных, каковы доступные решения для этого случая ?! извините за то, что много пишу.
Я использую React Navigation и вот иерархия экрана:
Switch -> Tab -> Stack (здесь мой родитель) - >act-native-tab -view -> (вот мой ребенок)
Когда я перехожу к любому экрану на том же уровне навигации по вкладкам или более глубоко, я получаю консоль, например: