React Cloud Firestore Not Fetching Data Properly - reactjs

I need to fetch all data from the collection but instead only getting one document. I will be grateful for you support. Below, I present the screenshots and code snippet regarding my concern.
enter image description here
enter image description here
import './App.css';
import db from './firebase';
import React,{useState,useEffect} from 'react';
function App() {
const [accounts,setAccounts]=useState([])
const fetchAccounts=async()=>{
const response=db.collection('accounts');
const data=await response.get();
data.docs.forEach(item=>{
setAccounts([...accounts,item.data()])
})
}
useEffect(() => {
fetchAccounts();
}, [])
return (
<div className="App">
{
accounts && accounts.map(account=>{
return(
<div>
<h1>Example</h1>
<h4>{account.date}</h4>
<p>{account.email}</p>
</div>
)
})
}
</div>
);
}
export default App;

Set state functions in React are async. It means that your values are not updated immediately.
So when you update your state in a loop, each time it updates the initial value of the state and because of that at the end of the loop, only 1 item is added to the array.
In order to fix the bug, you should use another variable and set your state after the loop:
import React, { useState, useEffect } from 'react';
import './App.css';
import db from './firebase';
function App() {
const [accounts, setAccounts] = useState([]);
const fetchAccounts = async () => {
const response = db.collection('accounts');
const data = await response.get();
const newAccounts = data.docs.map(item => item.data());
setAccounts(newAccounts);
}
useEffect(() => {
fetchAccounts();
}, [])
return (
<div className="App">
{
accounts && accounts.map(account => {
return(
<div>
<h1>Example</h1>
<h4>{account.date}</h4>
<p>{account.email}</p>
</div>
)
})
}
</div>
);
}
export default App;

Related

Failing to read data from firebase firestore using next.js getStaticProps

I am trying to read data from firebase using nextjs but I get back an empty page. Even when I console log, nothing gets returned. This is how my code looks like
import React, {useState} from 'react'
import { db } from '../firebase'
import { collection, getDocs } from "firebase/firestore";
const reference = collection(db, "students");
function Card(props) {
const { studentsData } = props
return (
<div>
<p>This is just a test</p>
{studentsData && studentsData.map(students => (
<p>{students.name}</p>
))}
</div>
)
}
export const getStaticProps = async () => {
const students = await getDocs(reference);
const studentsData = students.docs.map(doc => ({id: doc.id, ...doc.data() }))
console.log(studentsData);
return {
props: { studentsData }
}
}
export default Card
All I get back from this is just an empty page. Where could I be going wrong?.

How to update my global context and state

I have a state that I want to make global so that I can use it across multiple different components
and I am trying to do this through using context.
So I have my initial Component which gets the data and sets the global state, the issue I am having is when I try to use this state in the other components it seems to be empty because I believe my GlobalContext varibale is not updating so will be empty when the other components try to use the state. I cannot seem to figure out what I am missing to ensure my global state and context are both updated so that I can use them across the different components that require the data as well.
Can anyone figure out where I should update my context as well as my state
Component that gets the data initially:
import React from "react";
import { useState, useEffect, useMemo, useContext } from "react";
import axios from "axios";
import { GlobalContext } from "./Store";
function Map() {
// ------- global state
const [activities, setActivities] = useContext(GlobalContext);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
setActivitieData();
console.log("activities after useEffect", activities)
}, []);
const getActivityData = async () => {
console.log("calling")
const response = await axios.get(
"http://localhost:8800/api/"
);
return response.data;
};
const setActivitieData = async () => {
const activityData = await getActivityData();
setActivities(activityData);
console.log("Global activities state = ", activities);
};
return !isLoading ? (
<>
<MapComp
activityData={activities}
/>
</>
) : (
<div>
<p>Loading...</p>
</div>
);
}
export default Map;
GlobalStateStore component:
import React, {useState} from "react";
const initState = [];
export const GlobalContext = React.createContext();
const Store = ({children}) => {
const [activities, setActivities] = useState(initState);
return (
<GlobalContext.Provider value={[activities, setActivities]}>
{children}
</GlobalContext.Provider>
)
}
export default Store;
component I am trying to use the global state in but is empty:
import React, {useContext} from 'react';
import { GlobalContext } from "./Store";
function ActivityList() {
const [activities, setActivities] = useContext(GlobalContext);
let displayValues;
displayValues =
activities.map((activity) => {
return (
<div>
<p>{activity.name}</p>
<p>{activity.distance}m</p>
</div>
);
})
return (
<>
<p>Values</p>
{displayValues}
</>
);
}
export default ActivityList;
App.js:
function App() {
return (
<Store>
<div className="App">
<NavBar />
<AllRoutes />
</div>
</Store>
);
}
export default App;
Here's a barebones single-file version of your code that certainly works.
Since you aren't showing how you're mounting your <Map /> and <ActivityList /> components originally, there's not much more I can do to help you with that code, though I will note that it's useless to try and log activities in the same function that has just setActivities, since setState is async (and the function will have captured the earlier activities value anyway).
import React, { useContext, useState, useEffect } from "react";
const delay = (ms) => new Promise((res) => setTimeout(res, ms));
async function getActivityData() {
console.log("calling");
await delay(1000);
return [{ name: "foo", distance: 123 }];
}
function Map() {
const [, setActivities] = useContext(GlobalContext);
useEffect(() => {
getActivityData().then(setActivities);
}, [setActivities]);
return <>map</>;
}
const initState = [];
const GlobalContext = React.createContext();
const Store = ({ children }) => {
const [activities, setActivities] = useState(initState);
return (
<GlobalContext.Provider value={[activities, setActivities]}>
{children}
</GlobalContext.Provider>
);
};
function ActivityList() {
const [activities] = useContext(GlobalContext);
return <div>{JSON.stringify(activities)}</div>;
}
export default function App() {
return (
<Store>
<Map />
<ActivityList />
</Store>
);
}

Nextjs error - TypeError: Cannot read property 'useState' of null

I keep getting this error
TypeError: Cannot read property 'useState' of null
whenever I try pulling data from the firestore database. The error points to when I am using the useState and this is how my code looks like
import React from 'react'
import { useState } from 'react';
import { db } from '../firebaseconfig'
import { collection, getDocs } from "firebase/firestore";
const reference = collection(db, "students");
const [students, setstudents] = useState([]);
export const getStaticProps = async () => {
const data = await getDocs(reference);
setstudents(data.docs.map(doc => ({...doc.data(), id: doc.id})));
return {
props: students
}
}
function Card({students}) {
return (
<div>
{students.map(student => (
<h1>{student.name}</h1>
))}
</div>
)
}
export default Card
Where could I be going wrong?
In the code snippet you have provided, the state students does not have any other purpose than being sent as props to Card component.
Based on the nextjs docs (https://nextjs.org/docs/basic-features/data-fetching/get-static-props#using-getstaticprops-to-fetch-data-from-a-cms) , modify the code like this and try
import React from 'react'
import { db } from '../firebaseconfig'
import { collection, getDocs } from "firebase/firestore";
const reference = collection(db, "students");
export const getStaticProps = async () => {
const data = await getDocs(reference);
const students=data.docs.map(doc => ({...doc.data(), id: doc.id}));
return {
props: {
students
}
}
}
function Card({students=[]}) {
return (
<div>
{students.map(student => (
<h1>{student.name}</h1>
))}
</div>
)
}
export default Card
From React Docs there are rules to using Hooks.
React Hooks Rules
Your code should look like this:
function Card({students}) {
const [students, setstudents] = useState([]);
return (
<div>
{students.map(student => (
<h1>{student.name}</h1>
))}
</div>
)
}
This should solve your bug.
Change setstudents to setStudents and I suggest simplify your code:
import React, { useState } from 'react'
import { db } from '../firebaseconfig'
import { collection, getDocs } from "firebase/firestore";
function Card() {
const [students, setStudents] = useState([]);
const fetchStudents=async()=>{
const response=db.collection('students');
const data=await response.get();
setStudents(data.docs.map(doc => ({...doc.data(), id: doc.id}))
);
}
useEffect(() => {
fetchStudents();
}, [])
return (
<div>
{students && students.map(student => (
<h1>{student.name}</h1>
))}
</div>
)
}
export default Card
you are using 2 react imports. Make it one
try this:
import React, { useState} from 'react'

How to sync firebase with react functional components

I would like to sync my component React with Firebase but i use a functional component i found somes answers in internet but it's seems complicated and doesn't worked for me
and i can't use this : useEffect(() => { base.syncState('/', { context: this, state: 'messages' }) });
my code is
import React,{useEffect, useState} from 'react'
import Formulaire from './component/Formulaire'
import Message from './component/Message'
import {useParams} from 'react-router-dom'
import database from './Base'
import { getDatabase, ref, set,onValue } from "firebase/database";
function App() {
const [state , setState] = useState({
messages : {},
pseudo : useParams().pseudo,
})
const addMessage = (message) =>{
state.messages[`message-${Date.now()}`] = message
setState({pseudo : state.pseudo ,messages : state.messages})
}
const msg = Object.keys(state.messages)
const lastMessages = msg.map(key=>{
return <Message key={key} pseudo={state.messages[key].pseudo} message = {state.messages[key].message} />
})
return (
<div className="container-lg col-4 mt-5">
<div>
{lastMessages}
</div>
<Formulaire length={150} addMessage ={addMessage} pseudo={state.pseudo} />
</div>
)
}
export default App
And my firebaseApp code :
import { initializeApp } from 'firebase/app';
import { getDatabase } from "firebase/database";
// TODO: Replace with your app's Firebase project configuration
const firebaseConfig = {
apiKey: "AIzaSyB2CFjr32PoNdsnfvEgt_AijgE18lNKz2c",
authDomain: "chat-app-42ed5.firebaseapp.com",
projectId: "chat-app-42ed5",
storageBucket: "chat-app-42ed5.appspot.com",
messagingSenderId: "880643875911",
appId: "1:880643875911:web:9d04114b45bb40c2627d62",
measurementId: "G-MP1VZCGRDP"
};
const app = initializeApp(firebaseConfig);
// Get a reference to the database service
const database = getDatabase(app);
export default database
When you mount the App component, you can open a snapshot listener to RTDB, see docs. You do that in useEffect and also return a function from useEffect to destroy the listener when your component gets unmounted. It's called a "cleanup function", see React docs
It would look something like that:
function App() {
useEffect(() => {
const unsubListener = onValue(ref(rtdb_instance, '/YOUR_PATH'), (snapshot) => {
// Probably iterate over `snapshot.val()` and store it in your state
})
// Return cleanup function
return unsubListener;
}, [])
}
Note that the dependency array is empty here, meaning it won't change. Hence, it will only be executed on inital mount.
Also please note that the code above is not tested, so your milage might vary.
I use my function writeUserData() in AddMessage function after submit message to send to REALTIME DATABASE not in UseEffect() and after to get message after refresh page i use onValue() as you say in UseEffect() and in the same time i update my state with setState() ex: if (data) {
setState({messages : data.messages , pseudo : state.pseudo})
} return
import React,{useState,useEffect} from 'react'
import Formulaire from './component/Formulaire'
import Message from './component/Message'
import {useParams} from 'react-router-dom'
import database from './Base'
import { ref, set,onValue } from "firebase/database";
function App() {
const [state , setState] = useState({
messages : {},
pseudo : useParams().pseudo,
})
useEffect(()=>{
const resultDb = ref(database);
onValue(resultDb, (snapshot) => {
const data = snapshot.val();
if (data) {
setState({messages : data.messages , pseudo : state.pseudo})
} return
})
return resultDb
},[])
function writeUserData(message) {
set(ref(database), {
messages :message
});
}
const addMessage = (message) =>{
state.messages[`message-${Date.now()}`] = message
setState({pseudo : state.pseudo ,messages : state.messages})
writeUserData(state.messages)
}
const msg = Object.keys(state.messages)
const lastMessages = msg.map(key=>{
return <Message key={key} pseudo={state.messages[key].pseudo} message = {state.messages[key].message} />
})
return (
<div className="container-lg col-4 mt-5">
<div>
{lastMessages}
</div>
<Formulaire length={150} addMessage ={addMessage} pseudo={state.pseudo} />
</div>
)
}
export default App

TypeError: patients.map is not a function React Js

I am requesting some basic info from the back end using axios but for some reason unable to render the data on screen. Below is my basic App component using hooks and a map function to return a surname
import React, { useState, useEffect } from 'react';
import FullCalendar from '#fullcalendar/react'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction';
import { Router } from '#reach/router'
import 'bootstrap/dist/css/bootstrap.css'
import axios from 'axios'
import './custom.css'
const App = () => {
const [patients, setPatient] = useState([])
useEffect(() => {
axios.get('http://localhost:5000/api/patient').then(response => {
console.log(response.data)
setPatient(response.data)
})
}, [])
return (
<>
<div>
<ul>
{patients.map(p => (
<li>{p.surname}</li>
))}
</ul>
</div>
</>
)
}
export default App
When I check the dev tools I am bringing back all of data
I cannot see how my map function 'is not a function' can anyone help me out here please I get the below error message which is annoying
Try to use Async and Await for API call.
useEffect(function() {
async function fetchPatients() {
const response = await
fetch('http://localhost:5000/api/patient');
const json = await response.json();
setPatient(json.data);
}
fetchPatients();
}, []);
try this fixes:-
import React, { useState, useEffect } from 'react';
import FullCalendar from '#fullcalendar/react'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction';
import { Router } from '#reach/router'
import 'bootstrap/dist/css/bootstrap.css'
import axios from 'axios'
import './custom.css'
const App = () => {
const [patients, setPatient] = useState([])
useEffect(() => {
(async () => {
try {
// fetching all patirnts
let res = await axios.get("http://localhost:5000/api/patient");
setPatient(res.data);
} catch (err) {
console.log(err);
}
})();
}, []);
return (
<>
<div>
<ul>
{patients?.map(p => (
<li>{p.surname}</li>
))}
</ul>
</div>
</>
)
}
export default App
A working code, for anyone who stupidly wastes too much time on this problem in the future. The data was nested meaning I had to setPatient to response.data.data. I was then able to pull all required info using Axios
useEffect(() => {
axios.get('http://localhost:5000/api/patient').then(response => {
setPatient(response.data.data)
})
}, [])

Resources