React JS not able to display firebase data in jsx element - javascript

I'm fairly new to React JS and I've been working on one project where I need to first get data from the firebase firestore db and then display it on the page by creating new elements. I need to accomplish this without the whole page refreshing and only the rendered elements being displayed. I have fetched the data from the db and have put it into an array, after that I was trying to use the map function to go through the array and return an h1 element containing the data but it was not showing up on the page. I did a console.log on the data and it's showing up in the console as expected. My main question is, how do I return an h1 elements using the map function that will contain the data from the array?
import React, {useRef} from "react";
import {useHistory} from 'react-router-dom';
import '../connectApp.css';
import Navbar from './Navbar.js';
import SideBar from './sideBar.js';
import {db} from '../fbConfig';
import {auth} from '../fbConfig';
import ReactDOM from 'react-dom'
const App = () => {
const history = useHistory();
const data = [];
if(localStorage.getItem("isAuth") === 'null') { //NOTE - we are only able to store strings in localStorage
history.push('/');
}
var docRef = db.collection("posts");
docRef.onSnapshot(snapshot => {
let changes = snapshot.docChanges();
console.log(changes);
changes.forEach(change => {
if(change.type == "added") {
data.push({
imageUploader:change.doc.data().imageUploader,
imageCaption:change.doc.data().imageCaption,
imageUrl:change.doc.data().imageUrl
})
}
})
return <div>
{data.map(data => {
console.log(data)
})}
</div>
})
return (
<div className="container">
<Navbar />
<SideBar />
</div>
);
}
export default App
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

I found that by using the this.state method I was able to set a state for my data, store my data in an array, update the state, and then use the map function as was done previously to get the data and display it in a div.

Related

Store fetch data in a variable and use entire json as a prop in a react component

i have the next code, the app should get a json from an api and then pass the entire json as a prop so it can be treated in each component file and return the element to the screen.
The thing is i haven't found a way to just store the info from the fetch into a variable. if i just pass a json that is declared in the same file it would work just fine but can't make it work with the info from the fetch, the developer tools shows the json is being retrieved but it doesn't seem to accesed in the components, as you can see in the components part i tried to use globalData to use the json store in that variable but it breaks my app and the console says "Uncaught TypeError: Cannot read properties of undefined (reading 'name')" in which name is is the first element inside my json.
import logo from './logo.svg';
import './App.css';
import React, {useEffect, useState} from 'react';
import Title from "./components/Title"
import Summary from "./components/Summary"
import Skills from './components/Skills';
import Experience from './components/Experience';
import Sideprojects from './components/Sideprojects';
import Education from './components/Education';
import Interests from './components/Interests';
import Courses from './components/Courses';
import Picture from './components/Picture';
import ReactDOM from "react-dom";
var cvdata = here i have a json with a lot of info, if i just write props = {cvdata} it would work just fine
function App() {
// fetch('http://localhost:5000/api')
// .then(res => console.log(res))
let dataGlobal;
const getData = async () => {
const response = await fetch("http://localhost:5000/api");
const data = await response.json();
dataGlobal = data;
return data;
};
(async () => {
await getData();
console.log(dataGlobal);
})();
return(
<div className="App">
<div className='Upleft'>
<Title props = {dataGlobal}/>
<Summary props = {cvdata}/>
<Experience props = {cvdata}/>
<Education props = {cvdata}/>
</div>
<div className='Right'>
<Picture props = {cvdata}/>
<Skills props = {cvdata}/>
<Interests props = {cvdata}/>
<Courses props = {cvdata}/>
<Sideprojects props = {cvdata}/>
</div>
</div>
)
}
export default App;
Maybe something like this would help:
It can look kinda funky, but essentially the hook useEffect takes an array of states, which when change, fires the containing function. I pass an empty array as the second argument of useEffect to have the fetch for data only happen the first load of the component. The first argument is the function you want to fire, which MUST return undefined. async functions always return a promise, so to work around this, we instead nest an anonymous async function we call immediately so the async / await syntax is available to us.
hopefully the code example is clear enough. If you have any questions or I misunderstood your prompt, please let me know. Good luck! 👍👍
const { useState, useEffect } = React;
function App (props) {
const [ page, setPage ] = useState("loading");
useEffect(() => {(async () => {
const res = await fetch(someWebsite)
.catch(err => setPage(err.message));
if (!res) return;
const txt = await res.text();
setPage(txt);
})();}, []);
return (
<div>
This is the page: <br />
{ page }
</div>
);
}

React JS, Variable name is not saved when fetching data from API

The issue I got is that the fetched Data from API is not saved to a variable. Please look at the fearvalue, it's being called later and the value of that is an empty string.
APY component
export let fearvalue = [];
export const fearAndGreed = () => {
// 1. Create a new XMLHttpRequest object
let bitcoinAPY = new XMLHttpRequest();
// 2. Configure it: GET-request for the URL /article/.../load
bitcoinAPY.open("GET", "https://api.alternative.me/fng/?limit=10&date_format=us", false)
bitcoinAPY.onload = () => {
const data = JSON.parse(bitcoinAPY.response);
/*const saveStaticDataToFile = () => {
let blob = new Blob(['Welcome'],
{type: 'text/plain;charset=utf-8'});
saveStaticDataToFile(blob, "static.txt")
}*/
console.log(data)
fearvalue = data.data[0];
}
// 3. Send the request over the network
bitcoinAPY.send();
}
window.addEventListener('load', fearAndGreed)
fearvalue is being called in this component and it is a blank value. Can anyone help me with saving data to this variable?
import './App.css';
import './Apy_TAPI';
import './Bitcoin Fear&Greed';
import { DataFormatting } from './DataFormatting.js';
import { fearvalue } from './Bitcoin Fear&Greed';
import './App.css';
import './Apy_TAPI';
import './Bitcoin Fear&Greed';
import { DataFormatting } from './DataFormatting.js';
import { fearvalue } from './Bitcoin Fear&Greed';
function App() {
const test1 = "test1"
console.log(fearvalue)
return (
<div className="App">
<header className="App-header">
<p>
Bitcoin analyst tool
</p>
</header>
<div className='Text'>
<h1>
<img className="Image" src="https://alternative.me/crypto/fear-and-greed-index.png" alt="Latest Crypto Fear & Greed Index" />
</h1>
<h2>
https://bitinfocharts.com/pl/bitcoin/address/1P5ZEDWTKTFGxQjZphgWPQUpe554WKDfHQ <br />
<br />
{fearvalue} <br />
</h2>
</div>
</div>
);
}
export default App;
You need to save the response in a proper way. in React.js, you could use useState to create a state variable and set the response in it.
First, you need to save the response in a state variable:
import React, {useState} from 'react';
export const fearAndGreed = () => {
const [fearValue, setFearValue] = useState() // initialize with proper value according to your data type, it could be a empty array [] or an object {}.
let bitcoinAPY = new XMLHttpRequest();
bitcoinAPY.open("GET", "https://api.alternative.me/fng/?limit=10&date_format=us", false)
bitcoinAPY.onload = () => {
const data = JSON.parse(bitcoinAPY.response);
setFearValue(data.data[0]) // ------> set the fearValue here
}
bitcoinAPY.send();
}
window.addEventListener('load', fearAndGreed)
So far, the first part is done. but you need the fearValue in the other component. to achieve this, there are some solutions like using a Global State Manager like Redux or ContextApi. without them, your implementation would be tricky since you can't use the lifting state up technique because you didn't use fearAndGreed as a child component in the parent component (App).
In such cases, you can implement a custom hook with fearAndGreed function. since the function invokes once after the page loading, you can implement this by calling the API after your components did mount.
Let's make a custom hook with the current fearAndGreed function in this way:
import {useEffect, useState} from 'react';
export const useFearAndGreed = () => {
const [fearValue, setFearValue] = useState();
useEffect(() => {
let bitcoinAPY = new XMLHttpRequest();
bitcoinAPY.open("GET", "https://api.alternative.me/fng/?limit=10&date_format=us", false)
bitcoinAPY.onload = () => {
const data = JSON.parse(bitcoinAPY.response);
setFearValue(data.data[0]) // ------> set the fearValue here
}
bitcoinAPY.send();
}, [])
return fearValue;
}
Explanation:
With a few changes, fearAndGreed function becomes a custom hook useFearAndGreed.
The API will call in the useEffect after the component did mount (with an empty array of dependencies).
The hook will return the fearValue on every change.
Now, time to use this custom hook inside of the App component:
function App() {
const fearValue = useFearAndGreed()
return (
<div>
{fearValue}
</div>
);
}
export default App;
Note: I removed the other parts of implementation in the App component to simplify it. you should include your own implementation within.
Now, every time the App component did mount, the useFearAndGreed will be invoked and return the fearValue which can be saved in a constant fearValue to use in the div element.

Passing data from one component to another in React using formik

I've created a simple react component for a form with few input fields using formik. My form is rendered three times on my home page for three different type of users, but I only have one button that is outside the component and on click it should save the data inside the PersonalInformation component. This is how my code looks inside my App.js (ignore the users and data for now):
{users.map((data, i) => { return <PersonalInformation key={i} /> })}
<Button>Submit</Button> //this is the button that needs to save the data inside of PersonalInfo component od click
My question is how I can save the data inside the three forms on click on the button? In end-point on the back end I would like to get an array of three objects, each objects will contain info about each field in the form. I guess what I need is to pass data from PersonalInformation component to onClick()event in Button, but I am not sure how to do that with formik.
if you don't use any state management, context etc i think simplest way is you can pass reference to your save method upper.
import React, {useRef} from "react";
import PersonalInformation from "./PersonalInformation";
import "./styles.css";
export default function App() {
const saveRef = useRef(null)
return (
<div className="App">
<PersonalInformation passSave={(ref) => saveRef.current = ref}/>
<button onClick={() => saveRef.current()}> save </button>
</div>
);
}
//---------------------------------------------------------
import React, { useCallback, useEffect, useRef } from "react";
const PersonalInformation = ({passSave}) => {
const formInput = useRef(null);
const save = useCallback(() => {
console.log(formInput.current.value)
}, [formInput])
useEffect(()=>{
passSave(save)
}, [passSave, save])
return (
<input type="text" ref={formInput} />
)
}
export default PersonalInformation;

Hacker Rank clone in React

I'm making a Hacker rank clone project in React, and so far I tried to get all the New Posts from the API.
Since the API only gives me id's I was just able to map over the piece of state that holds that information. But now I want to get the whole data from every id that I got , and then display all the posts. It's been really confusing for me, and i really need some help. Well, to resume everything: I got the id's from a api call and stored it in my state. Now I want to get all of the id's and make another request, but this time I'll get the info based on that specific Id. Here's the code:
import React, { useState } from "react";
import "./styles.css";
import TopList from "./components/TopList";
export default function App() {
const [state, setState] = useState({
data: [23251319, 23251742, 23251158],
results: []
});
const fetcher = id => {
fetch(`https://hacker-news.firebaseio.com/v0/item/${id}.json?print=pretty`)
.then(res => res.json())
.then(data => {
console.log(data);
setState({
results: data
});
});
};
return (
<div>
<TopList data={state.data} fetcher={fetcher} />
</div>
);
}
import React from "react";
import Top from "./Top";
function TopList({ data, fetcher }) {
const mapped = data.map(item => (
<Top fetcher={fetcher} id={item} key={item} />
));
return <div>{mapped}</div>;
}
export default TopList;
import React from "react";
function Top({ id, fetcher }) {
fetcher(id);
return (
<div>
<h1>Hello from top</h1>
</div>
);
}
export default Top;
As I told you in the comments, the fetcher() function already gets the data of each item using the IDs you have from the first request. I think that a good place to call this function is the TopStoryComponent, as there will be an instance of this component for each ID in the list.
import React from "react";
function TopStoryComponent({ identification, fetcher }) {
// this will print the data to the console
fetcher(identification);
return <div>{identification}</div>;
}
export default TopStoryComponent;
Let me know if it helps you get what you need!

How to pass info with React Router to the new page?

I've made a quick CodeSandBox example what I am after. I have a "Our Courses" section on the landing page with the button "Read more". Once the "Read more" button gets clicked, depending on the Course it would render that information. Now I got the button to work but now I am stuck and can't figure out how to pass relevant information to the redirected page. Now let's say I want to get the Course "Title" and "Description" get passed onto to the redirected page. How can I do that?
CodeSandBox link here - Link here
Your CardInfo component can look-up the course detail from your courses repository.
To perform the look-up you can determine which card was selected by using the react-router useParams hook; this allows you to determine which course identifier was passed via the selected route i.e.
import React from "react";
import courses from "./courses";
import { useParams } from "react-router-dom";
const CardInfo = () => {
const { id } = useParams();
const course = courses.find(course => course.id === id);
return (
<div>
<h1>{course.title}</h1>
<p>{course.description}</p>
</div>
);
};
export default CardInfo;
A complete working example of this can be seen here (its a fork of your CodeSandBox).
You can pass data between Routes by using the object version of the to prop of Link component, so change your Link component to this:
//Card.jsx
<Link
to={{
pathname: `/card/${course.title}`,
state: {
description: course.description
}
}}>
<button className="btn">Read more</button>
</Link>
Then in your CardInfo.jsx component you can access this data by props.location.state.description
import React from "react";
const CardInfo = (props) => {
console.log(props)
return (
<div>
<h1>
How can I pass course title here depending on which button I click
</h1>
<p>{props.location.state.description}</p>
</div>
);
};
export default CardInfo;
Hope it helps :)
In your CardInfo component you can access the id provided by the route using the useParams from your react-router-dom library.
I'm using your <Route path="/card/:id" component={CardInfo} /> for reference.
Implement it like this:
import React from 'react'
import { useParams } from 'react-router-dom'
const CardInfo = () => {
const { id } = useParams()
return <div>Card ID: {id}</div>
}
export default CardInfo
Now that you've got the id you should be able to use it for whatever you need.
There are multiple approaches to pass this data:
You can pass data through the link state like this:
<Link
to={{
pathname: `/card/${course.title}`,
state: { description: course.description }
}}
>...</Link>
And then read it in the CardInfo component like this:
import { useLocation } from "react-router-dom";
const CardInfo = () => {
const location = useLocation();
console.log(location.state) // { description: 'Lorem ipsum...' }
However, the best way to do this is to pass the course id in the URL and read the rest of the information from the courses.js file:
This is already correct, you accept the course id as URL paramter:
<Route path="/card/:id" component={CardInfo} />
Pass the course id in the link:
<Link to={`/card/${course.id}`}>
Read the id parameter from the URL and get the rest of the course information from the courses file:
import { useParams } from "react-router-dom";
import courses from './courses'
const CardInfo = () => {
const params = useParams();
console.log(courses[params.id]);

Categories