I have a functional component that requires receiving parameter (i.e. props.rosterMonth) from the parent component and then retrieving data from the database, finally pass the result to the children component.
My problem is, how to set the initial state for the children component?
import {useEffect,useReducer} from 'react';
import Roster from '../../../utils/Roster';
import RosterWebContext from '../../../utils/RosterWebContext';
import Testing from './Testing';
export default function VVTable(props){
let dataReducer=(state,action)=>{
switch (action.type){
case 'updateRosterMonth':
return action.value;
default:return state;
}
}
const [contextValue, updateContext] = useReducer(dataReducer,{});
useEffect(()=>{
const getData = async () => {
console.log("Undo:Get Data from DB");
let roster = new Roster();
let rosterList= await roster.get(props.rosterMonth.getFullYear(),props.rosterMonth.getMonth()+1);
updateContext(
{
type:'updateRosterMonth',
value:{rosterList}
}
);
}
getData();
},[props]);
return(
<table id="rosterTable">
<RosterWebContext.Provider value={[contextValue, updateContext]}>
<Testing/>
</RosterWebContext.Provider>
</table>
)
}
This is the Testing component.
import {useContext,useEffect} from 'react';
import RosterWebContext from '../../../utils/RosterWebContext';
export default function Testing(props){
let [contextValue,updateContext]=useContext(RosterWebContext);
useEffect(()=>{
console.log(contextValue.rosterList);
},[contextValue])
return(
<tbody>
</tbody>
)
}
Currently, I set the initial state to an empty object, so the child component 'Testing' may receive an empty object, to prevent the undefined object error, I need to write some code to check the incoming context value. If I can set the database value to the initial state, I can remove those checking code.
The data from the database will always be delayed because it has to be retrieved via that API call from the server, (unless you are doing server side rendering). So you have to deal with the fact that at the beginning you don't have a rosterlist..
What I would do in this case is check if contextvalue.rosterList is defined and if it's not display a nice loading spinner to the user, something like this:
import {useContext,useEffect} from 'react';
import RosterWebContext from '../../../utils/RosterWebContext';
export default function Testing(props){
let [contextValue,updateContext]=useContext(RosterWebContext);
useEffect(()=>{
console.log(contextValue.rosterList);
},[contextValue])
return(
!!contextValue.rosterList?(
<tbody>
</tbody>
):(
<span>Loading Roster</span>
)
)
}
Related
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>
);
}
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.
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!
I am trying to do some kind of online shop for myself and I got a problem.
I want to render my shopping cart size in the NavBar component (which is on every page).
I created a Cart Items service where I put all my added items, and it also has functions to addItem, removeItem, getCart, getCartSize.
When I click on Add/Remove on specific product, I would like to do that the value on NavBar with cart size would be changing depending on the cart size (from getCartSize method). I already tried to use useEffect hook, but it does not recognize when the value of cartSize is changed, how can I do that?
This is what I have done already.
navbar.jsx:
//...
//...
import {getTotalCount} from '../../services/myCart';
export default function Navbar() {
// ...
const [count, setCount] = useState();
useEffect(() => {
setCount(getTotalCount());
console.log('counto useeffect');
},[getTotalCount()]);
//},[getTotalCount]); doesn'work also.
//},[count]); doesn'work also.
return (
<>
<header className="navbar">
<Link className="navbar__list-item__home-icon" to="/"><span><FaHome/></span></Link>
<Link className="navbar__list-item" to="/products">Products</Link>
<h2>cart size--> {count}</h2>
<Link className="navbar__list-item__cart-img" to="shopping-cart"><span><FaShoppingCart/></span></Link>
</header>
</>
);
}
myCart.js all functions work fine and I call them when I click add/remove button in on my component in the products page.
var InTheCart = [
];
var totalCount = 0;
export function AddToCart(item) {
// ... logic
totalCount++;
}
export function ContainsInTheCart(id) {
return InTheCart.findIndex(x=> x.item.id == id) != -1 ? true: false;
}
export function RemoveFromCart(id) {
// ... logic
totalCount--;
}
export function getCart() {
return InTheCart;
}
export function getTotalCount() {
return totalCount;
}
React is called react because it re-renders when it reacts to something that changed.
For that to happen, the react components need to know, somehow, that something changed.
In the code example you show, the totalCount (which global access provided by exported function getTotalCount) is independent from react component tree, so that data can change without react knowing it.
So, the question is: how to make your react component aware of those changes?
A few mechanisms exist, here are a few of them:
Use a global state manager like redux, with redux actions and reducer to mutate the state and useSelector in the component that will make them aware of any change, and rerender
React context which will hold the cart state. That context can export both that data, and th function that will mutate the data, so they can be shared between components that have access to that context provider.
Your context could be used in the component that way:
const cartContext = useContext(CartContext)
const { cartState, addToCart, removeFromCart } = cartContext
const { totalCount, inTheCart } = cartState
[...somwhere later...]
<ul><li onClick={() => removeFromCart(index)}>{inTheCart[index].name}</li></ul>
<footer>{`${totalCount} items`}</footer>
I let you build the context object around your existing functions ;)
A simple solution is to lift the state up. Create the state in your layout file from where Header and Cart can access the count as Props. useEffect will be invoked whenever there is a change in the state or props of a component.
I'm using React and Redux to build a website and I have the code below for AppInfo component. I have result variable in the render method which is initialized before return statement. At first the result is an empty string but once the state changes it is set to an object which contains various app attributes. I want to display the result variable inside a div. The result always stays an empty string although I do see that the redux state is updated. In addition if call directly this.props.appId inside the div the updated state is indeed displayed. Why the result variable doesn't work?
This is my code:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { connect } from 'react-redux';
class AppInfo extends Component {
render() {
const { appInfo } = this.props;
const { appId } = appInfo;
let result = '';
if (appId) {
result = JSON.stringify(appInfo);
}
return (
<div>
{result}
{`JSON.stringify(appInfo) = ${JSON.stringify(appInfo)}`}
{`this.props = ${JSON.stringify(this.props.appInfo)}`}
</div>
);
}
}
AppInfo.propTypes = {
appInfo: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
appInfo: state.app
});
export default connect(mapStateToProps, null)(AppInfo);
Could you try to use result = JSON.stringify(this.props.appInfo);?
I think the issue might be related to the first 2 constโs you create.