I use react hooks,firebase to build a react native app.
I am pretty struggling about using Hooks with FlatList.
I am trying to creating pagination with Firestore. However, I am not sure how to trigger onEndReached using useEffect
It is what I tried:
const [isFetching, setIsFetching] = useState(false)
useEffect(() => {
if(isFetching == false){
_initFirestoreQuery()
}
}, [])
_initFirestoreQuery = async()=>{
const limit = 6
const initialQuery = firebase.firestore().collection('xxxx').orderBy('displayName', 'desc').limit(limit)
const documentSnapshots = await initialQuery.get()
const documentData = documentSnapshots.docs.map(document => document.data());
const lastVisible = documentData[documentData.length - 1].displayName;
setLast(lastVisible)
setData(documentData)
setIsFetching(true)
}
_moreFirestoreQuery = async () =>{
if(isFetching == true){
const limit = 6
const additionalQuery = firebase.firestore().collection('xxxx').orderBy('displayName', 'desc').startAfter(last).limit(limit)
const documentSnapshots = await additionalQuery.get();
const documentData = documentSnapshots.docs.map(document => document.data());
const lastVisible = documentData[documentData.length - 1].displayName;
setLast(lastVisible)
setData(data =>[...data,...documentData])
}
}
<FlatList
onEndReached ={_moreFirestoreQuery}
...
>
Any Idea of doing this if it is impossible how could I do it and is there any alternative for doing this
Related
Suppose we have this scenario: we need to make a request to an API to get data on number of books available. If books > 0, we must trigger
some sort of popup with a function which is provided to us. The books need to be stored into the redux store for other components to use. The codebase already uses redux-thunk and redux-thunk-middleware.
What would be the best implementation using a hook and why? (displayPopUp is the function that we must use to trigger the pop-up)
1)
const useBooksNotification = () => {
const dispatch = useDispatch();
const [shouldShowNotification, setShouldShowNotification] = useState(false);
const books = useSelector(selectAvailableBooks);
useEffect(() => {
if (shouldShowNotification) {
setShouldShowNotification(false);
if (books.length > 0) {
displayPopUp();
}
}
}, [shouldShowNotification, books]);
const showNotification = async () => {
if (!shouldShowNotification) {
await dispatch(fetchBooks);
setShouldShowNotification(true);
}
};
return {
showNotification,
};
};
or 2)
const useBooksNotification2 = () => {
const dispatch = useDispatch();
const showNotification = async () => {
{
const response = await dispatch(fetchBooks);
const books = response.value;
if (books.length > 0) {
displayPopUp();
}
}
};
return {
showNotification,
};
};
Personally, I prefer 2 since to me it is much more readable but someone told me 1 is preferable i.e listening to the selector for the books instead of getting the books directly from the action/API response. I am very curious as to why this is? Or if there is an even better implementation.
I would understand using a selector if there was no displayPopUp function given to us and instead there was some implementation like so:
const BooksNotification = () => {
const dispatch = useDispatch();
const books = useSelector(selectAvailableBooks);
const showNotification = () => {
dispatch(fetchBooks);
};
return books.length > 0 ? <h1>Pretend this is a pop-up</h1> : null;
};
const SomeComponent = () => {
<div>
<h1>Component</h1>
<BooksNotification />
</div>
}
I am trying to record video while using BlazePose with React Native. Wherever I add in cameraRef.current.camera.recordAsync() into causes the video to freeze and app to crash.
From what I've found, it might need to go in the handleCameraStream but I am unsure. Here is that method:
const handleCameraStream = async (
images: IterableIterator<tf.Tensor3D>,
updatePreview: () => void,
gl: ExpoWebGLRenderingContext) => {
const loop = async () => {
// const video = cameraRef.current.camera.recordAsync()
// Get the tensor and run pose detection.
const imageTensor = images.next().value as tf.Tensor3D;
const startTs = Date.now();
const poses = await model!.estimatePoses(
imageTensor,
undefined,
Date.now()
);
const latency = Date.now() - startTs;
setFps(Math.floor(1000 / latency));
setPoses(poses);
tf.dispose([imageTensor]);
if (rafId.current === 0) {
return;
}
// Render camera preview manually when autorender=false.
if (!AUTO_RENDER) {
updatePreview();
gl.endFrameEXP();
}
rafId.current = requestAnimationFrame(loop);
};
loop();
};
And here is my useEffect:
useEffect(() => {
async function prepare() {
rafId.current = null;
// Set initial orientation.
const curOrientation = await ScreenOrientation.getOrientationAsync();
setOrientation(curOrientation);
// Listens to orientation change.
ScreenOrientation.addOrientationChangeListener((event) => {
setOrientation(event.orientationInfo.orientation);
});
// Camera permission.
await Camera.requestCameraPermissionsAsync();
// Wait for tfjs to initialize the backend.
await tf.ready();
// Load model
const model = await posedetection.createDetector(
posedetection.SupportedModels.BlazePose,
{
runtime: "tfjs",
enableSmoothing: true,
modelType: "full",
}
);
setModel(model);
// Ready!
setTfReady(true);
}
prepare();}, []);
And finally the TensorCamera
<TensorCamera
ref={cameraRef}
style={styles.camera}
autorender={AUTO_RENDER}
type={cameraType}
// tensor related props
resizeWidth={getOutputTensorWidth()}
resizeHeight={getOutputTensorHeight()}
resizeDepth={3}
rotation={getTextureRotationAngleInDegrees()}
onReady={handleCameraStream}
/>
const [loggedInData, setLoggedInData] = useState([]);
const getLoginFromCache = async() => {
try{
let logData = await AsyncStorage.getItem('#MyDish:loginData');
let parsed = await JSON.parse(logData);
console.log(parsed);
setLoggedInData(parsed);
}
catch(error){
console.log(error);
}
}
getLoginFromCache()
console.log(loggedInData);
the result console.log(loggedInData) is always empty. whereas when i console.log(parsed) doesn't return empty
Use redux persist for store data on cache and to state.
https://www.npmjs.com/package/redux-persist
React set state is async, so console.log(loggedInData); will always print the initializtion state of loggedInData, in this case this state is an empty array
Try to wrap your getLoginFromCache function inside an useEffect like this:
const [loggedInData, setLoggedInData] = useState([]);
useEffect(() => {
const getLoginFromCache = async() => {
try{
let logData = await AsyncStorage.getItem('#MyDish:loginData');
let parsed = await JSON.parse(logData);
console.log(parsed);
setLoggedInData(parsed);
}
catch(error){
console.log(error);
}
}
getLoginFromCache()
}, [])
and if you want tracking your loggedInData state, you can use another useEffect to log that one:
useEffect(() => console.log(loggedInData),[loggedInData])
I am using redux in react native , When the state of redux changes, useEffect is not executed,
here is my code
const message = useSelector(state => {
const { privateChat } = state
const chatObj = privateChat.filter(s => s.user === replyer) // chatObj is an object
console.log('changed')
return chatObj[0]
})
useEffect(() => {
console.log('message1', message)
}, [message])
every time the 'changed' was printed, useEffect did not print out the data,I dont konw what went wrong
This might help
const privateChat = useSelector(state => state.privateChat);
const chatObj = privateChat.filter(s => s.user === replyer) // chatObj is an object
console.log('changed');
useEffect(() => {
console.log('message1', chatObj)
}, [privateChat]);
I currently have a react native app with a nodeJS backend. I using a function to get the data from the backend, then using that data to conditional render a button in my app.
My problem is that as soon as the app loads i keep getting undefined then true and hence the functionality does not work due to the undefined value. Does anyone know why that might be happening?
Here is my code:
const [data,setData]=useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const [refreshing, setRefreshing] = useState(false);
const [isEnabled, setIsEnabled] = useState(data.locked);
const [activated, setActivated] = useState(data.activated);
const loadData = async () => {
setLoading(true);
const response = await Api.getData();
setLoading(false);
if(refreshing)
setRefreshing(false);
if (!response.ok){
return setError(true);
}
setError(false);
setData(response.data)
if(response.data.locked===true)
setIsEnabled(true);
};
useEffect(() => {
loadData();
}, [data.locked]);
console.log(data.activated)
const activate = ()=>{
setActivated(true);
}
return(
{activated != true ?
<View style={{justifyContent:'flex-start',
alignItems:'flex-start',marginLeft:-10}}>
<Button title='Activate' onPress={activate}/>
</View>
:
null
}
)
data.activated prints out the following
undefined
undefined
undefined
undefined
true
true
true
true
true
and the button is getting displayed when it's not supposed to.
console.log(data.activated)
Will get called a few times before loadData is done so it will be undefined until setData is done setting data
EDIT:
This is how I would have written the component:
const [loading, setLoading] = useEffect(true)
const [data,setData] = useEffect(null)
useEffect(()=>{loadData()},[])
useEffect(()=>{if(data){setLoading(false)},[data]}
return (
{!loading?<THE BUTTON>:null}
)