How to share data from useState in React to another Component - reactjs

Hey guys let me quickly explain my problem.
I currently have Component in which User can Search something. And after they Click on a Button I get the Data from Firebase which is then stored in a useState which I map afterwards. This whole operation is in one function.
But for now I show the result at the same Page because I dont know how to transfer the data in the useState to the other component.
const handleClick = async () => {
const kurzRef = collectionGroup(db, 'kurzwaffensub' );
const MOD = query(kurzRef,where("kurzModell", "==", `${kurzModell}` ));
if(kurzModell) {
const getWaffenDaten = async () => {
const modell = await getDocs(MOD);
const data = [];
for (const doc of modell.docs) {
const parentDoc = await getDoc(doc.ref.parent.parent);
const { Name, avatar,avatarPath, Erfahrung, Adresse, Schützenverein } = parentDoc.data();
const waffenbilderRef = collection(db, 'users', doc.data().uid, 'waffenbildersub')
const subCollectionDocs = await getDocs(waffenbilderRef)
const subCollectionData = subCollectionDocs.docs.map((doc) => {
return { id: doc.id, ...doc.data()}
})
data.push({
...doc.data(),
Name,
subCollectionData,
avatar,
avatarPath,
Erfahrung,
Adresse,
Schützenverein
});
}
setTest(data)
}
getWaffenDaten()
}
After that operation I just return the Result in the same Page . And I want to change the page after the onClick event with the Result. Because I dont want to see the User Interface of the Search Component.
Perhabs its pretty simple but Im still a beginner and would be very glad if you can help me out and teach me something new and important.

You can do this in multiple ways:
You can pass search query as URL parameter if you using router and fetch the data from result page
You can use state management tool like Redux or built in context api.

Related

useEffect and state management library

I have this problem that I am trying to understand and solve. I want to fetch data in the main component and allow editing of this data. The problem is that the first time the data is properly loaded into the state but if I go back to the previous page where the table is and enter to edit another record then until I re-render the page the data from the previous record are in the state. I use Zustand to pass data between components. Please help guys :(
const { id } = useParams<string>();
const setData1 = useStore((state) => state.setData1)
const setData2 = useStore((state) => state.setData2)
React.useEffect(() => {
async function fetchData() {
const response = await getExampleData(id);
setData1(response.name);
setData2(response.values);
}
fetchData();
}, [id]);
return(
<ComponentData1/>
<ComponentData2/>)
And in i.e. ComponentData1 i'm using this below.
const data1 = useStore((state) => state.data1)

React Recoil: State not being saved across navigation to different URLs within App

I'm getting started with Recoil for a React App, but running into some issues, or at least some behavior I'm not expecting.
I'd like to be able to use one component to render many different "views" based on the URL. I have a useEffect in this component that switches based on the location.pathname and based on that pathname, it'll make an API call. But before it makes the API call, it checks the length of the atom to see if it's empty or not, then will call the API and set the atom based on the API call.
However, when I navigate to a different URL and come back to one I've already visited, the API is called again, even though I've previously set the state for that URL.
The behavior I'm expecting is that once a URL has been visited and the return from the API is stored in an Atom, the API call isn't made again when leaving the URL and coming back.
Relevant code below:
Atom.js
export const reports = atom({ key: "reports", default: { country: [], network: [], }, });
the one component that will render different data based on the reports atom.
import { useRecoilState } from "recoil";
import { reports } from "../globalState/atom";
const TableView = ({ columns, }) => {
const location = useLocation();
const [report, setReport] = useRecoilState(reports);
const currentView = location.pathname.split("/")[1];
useEffect(() => {
const getReportsData = async () => {
switch (location.pathname) {
case "/network":
if (report[currentView].length === 0) {
const response = await fetch("/api");
const body = await response.json();
setReport(
Object.assign({}, report, {
[currentView]: body,
})
);
console.log('ran')
break;
}
getReportsData();
}, [])
As previously mentioned, that console.log is ran every time I navigate to /network, even if I've already visited that URL.
I've also tried doing this with selectors.
Atom.js
export const networkState = atom({
key: "networkState",
default: networkSelector,
});
export const networkSelector = selector({
key: "networkSelector",
get: async ({ get }) => {
try {
const body = await fetch("/api/network").then((r) => r.json());
return body;
} catch (error) {
console.log(error);
return [];
}
}
Component
import {useRecoilStateLoadable} from "recoil"
import {networkState} from "../globalState/atom";
const Table = ({columns}) => {
const [networkData, setNetworkData] =
useRecoilStateLoadable(networkState);
And then a switch statement based on networkData.state
}
Any help would be greatly appreciated, thank you!

How I can display only one object from API array Reactjs

How I can display only one object from [data.hits]? Ive tried map(), filter, also setRecipes([data.hits.recipe[0]]); etc ... and it doesn't work. Currently, it shows 10 objects on the website but I need only one. Thank you for any help.
const [recipes,setRecipes] = useState ([]);
useEffect(()=>{
getReciepes();
},[query]);
const getReciepes = async () => {
const response = await fetch (`https://api.edamam.com/search?
q=${query}&app_id=${APP_ID}&app_key=${APP_KEY}`);
const data = await response.json();
setRecipes(data.hits);
console.log(data.hits);}
I dont know how I did not notice this. Here is a simple solution :
const list=[...data.hits]
list.length = 1
setRecipes(list);
console.log(list);
}

Make a second API call and return data

I need some help figuring out an issue.
I'm working on a web app and basically I make an API call which is an array of data to get someone's details and return them on the page, but for one param (editedBy) I get the person' id. So, I was asked to make another API call from where I can get that person's name.
import React from 'react';
import {getData} from '.api/calls';
import { connect } from "react-redux";
import {getEditedBy} from './api/calls';
const PersonDetails = ({userId}) => {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
const [editedBy, setEditedBy] = useState('')
const setDetails = user => {
setFirstName(user.firstName);
setLastName(user.lastName);
}
useEffect(() => {
getData(userId).then(res => {
setDetails(res.data)
});
getEditedBy(userId).then(res => {
setEditedBy(res.fullName)
});
}, [userId])
return (
<div>
<p>First Name: {firstName}</p>
<p>LastName: {lastName}</p>
<p>Edited By: {editedBy}</p>
</div>
)
}
export default connect(
state => ({
userId: state.user.userId
})
)(PersonDetails);
How can I return the person's full name and keep that value in place, instead of the id? Any help is appreciated.
This should cover your case:
useEffect(() => {
async function getUserDetailsAsync() {
const userData = (await getData(userId)).data;
const editedBy = (await getEditedBy(userData.editedBy)).data;
setDetails(userData);
setEditedBy(editedBy.fullName);
}
getUserDetailsAsync();
}, [userId]);
If you're not a fan of the await syntax for some reason you can go with the .then chaining but in any case you should make the second API call dependent on the first one.
useEffect(() => {
getData(userId).then(res => {
const userData = res.data;
getEditedBy(userData.editedBy).then(res => {
const editedBy = res.data;
setDetails(userData);
setEditedBy(editedBy.fullName);
});
});
}, [userId]);
In your current solution, you're firing 2 requests simultaneously which will cause completely nondeterministic result for you. First of all, you're querying for the fullName not of the person who edited the post, but for the same person you just queried(if I understood your context correctly). Second, your state will be updated at different times due to the independent requests. Third - one of the requests may fail while the other succeed, thus leaving your component with inconsistent state. Furthermore, you might have problems with trying to update an already unmounted component and you should have this in mind.

Looping set state react + firestore

I'm trying to create a user profile page for my app, for this page I'm trying to get a doc with some user information from firestore, and populate fields that the user can click on and to change. When I added the setTags function to the db call below, it resulted in an infinite loop. Can anyone explain why this happens and how to fix it? I'm very new to using react hooks.
const UserProfile = ({history}) => {
const description = useRef('');
const name = useRef('');
const {currentUser} = useContext(AuthContext);
let [tags, setTags] = useState('');
let uData;
db.collection('Users').doc(currentUser.uid).get().then(doc => {
console.log("checking db")
console.log(doc.data())
uData = doc.data();
description.current = uData.description;
name.current = uData.name
setTags(uData.tags)
})
}
Functional components are run on every render. That means that on every rerender, you open the database to search for the current user, then set the tags. Crucially, updating the state always causes a rerender! This is a core feature of React that allows implicit updating and is one of the main reasons to use React in the first place.
If you want something to be run only once, you can still do that, but you need to simulate componentDidMount() from a class component. So, you can use useEffect:
// Add this import in
import { useEffect } from 'react';
const UserProfile = ({history}) => {
const description = useRef('');
const name = useRef('');
const {currentUser} = useContext(AuthContext);
let [tags, setTags] = useState('');
let uData;
useEffect(() => {
db.collection('Users').doc(currentUser.uid).get().then(doc => {
console.log("checking db")
console.log(doc.data())
uData = doc.data();
description.current = uData.description;
name.current = uData.name
setTags(uData.tags)
})
}, []); // Empty dependency list means this will only run on first render
}

Resources