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.
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>
);
}
I have a 3 files:
Main component,
File with states that are stored in local storage
A file with a reset function for resetting these same states to default
values.
I import the file with the states and reset file in the main component and everything is ok. But when I try use reset function for set localState value to default, i got error โError: Invalid hook call. Interceptors can only be called inside the body of a functional component. "
I read the documentation on react, but I did not understand the error
First file code:
import React from "react";
import { LocalStorage } from "./localState";
import { resetLocalStorage } from "./resetLocalState";
function App() {
const localState = LocalStorage(); // local storage keys
const resetState = () => resetLocalStorage(); // reset local storate states
return (
<div>
<button onClick={() => resetState()}>Refresh State to default</button>
<br />
<button
onClick={() => localState.setLocalStorageState("State was changed")}
>
Change State
</button>
<p>{localState.localStorageState}</p>
</div>
);
}
export default App;
Second file code:
import { useState, useEffect } from "react";
const useLocalStorageList = (key, defaultValue) => {
const stored = localStorage.getItem(key);
const initial = stored ? JSON.parse(stored) : defaultValue;
const [value, setValue] = useState(initial);
useEffect(() => {
localStorage.setItem(key, JSON.stringify(value));
}, [key, value]);
return [value, setValue];
};
//local storage keys
export const LocalStorage = () => {
const [localStorageState, setLocalStorageState] = useLocalStorageList(
"State",
"Default Value"
);
return { localStorageState, setLocalStorageState };
};
Third file code
import { LocalStorage } from "./localState";
export const resetLocalStorage = () => {
const localState = LocalStorage(); //local storage keys
localState.setLocalStorageState("Default Value");
};
Link to SandBox
I didnt see anything to reset all states in your resetLocalStorage(). I assume you will keep track of all the 'local storage keys' and define reset-functions for each. This example modifies your hook to return a third function to reset the state so another reset-function doesn't have top be defined.
https://codesandbox.io/s/smoosh-sound-0yxvl?file=/src/App.js
I made few changes in your code to achieve the use case you were trying to achieve. (Let me know my implementation is suffices your use case)
The resetLocalStorage is not starting with use That's why you were getting the previous error.
After renaming that function to useResetLocalStorage, still it will not work since -
you were calling the custom hook onClick of button. This breaks one react hook rule which is react hooks must not be called conditionally https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level
I've been studying react and developing an app, but i got a problem using context. In one component I create the context and provide its value, but when I try to use the current value of context in another component, I have the default value. Code:
Component One:
export const OwnerInformationContext = React.createContext({})
function NameChoose() {
...
const [ownerInformation,setOwnerInformation] = useState({})
function onpressSubmitButton(e : FormEvent) {
e.preventDefault();
...
setOwnerInformation({name:'name',roomId:'id',owner:'true'})
}
return(
<div className="page-container">
<OwnerInformationContext.Provider value={ownerInformation} />
...
<form onSubmit={onpressSubmitButton}>
...
</form>
...
);
}
export default NameChoose;
So when i try to use by:
import { OwnerInformationContext } from '../NameChoose/index'
function ComponentTwo(){
const consumeOwnerContext = useContext(OwnerInformationContext)
useEffect(() => {
console.log(consumeOwnerContext)
}, [])
return <h1>test</h1>
}
I got the default value provide in component one, that's {}.
It looks like your context provider is not actually wrapping any components, as it has a self-closing tag:
<OwnerInformationContext.Provider value={ownerInformation} />
It should be:
<OwnerInformationContext.Provider value={ownerInformation}>
{/* Your child components here will have access to the context */}
</OwnerInformationContext.Provider>
You are using useEffect as ComponentDidMount meaning only at start(mount) the value will be console log.
you should give consumeOwnerContext as a dependency to useEffect like this
useEffect(()=>{
console.log(consumeOwnerContext);
},[consumeOwnerContext]);
And rename consumeOwnerContext to consumeOwnerValue, because you are getting the value out of the context using useContext.
After that when you will click on submit button you should have ComponentTwo console log it.
import React, { useState, useEffect, useContext } from "react";
export const OwnerInformationContext = React.createContext({});
function ComponentTwo() {
const consumeOwnerContext = useContext(OwnerInformationContext);
useEffect(() => {
// You are using consumeOwnerContext inside useEffect, in that case add
// it as dependency if you want to see the updated consumeOwnerContext value
console.log(consumeOwnerContext);
}, [consumeOwnerContext]);
return <div>test</div>;
};
function NameChoose() {
const [ownerInformation, setOwnerInformation] = useState({});
function onpressSubmitButton(e) {
e.preventDefault();
setOwnerInformation({ name: "name",roomId: "id",owner: "true",});
}
return (
// The 'OwnerInformationContext.Provider' has to wrap the component
// that will use its context value. In your case, ComponentTwo
// has to be a child of NameChoose.
<OwnerInformationContext.Provider value={ownerInformation}>
<div className="page-container">
<form onSubmit={onpressSubmitButton}>
<button type="submit">Submit</button>
</form>
</div>
<ComponentTwo />
</OwnerInformationContext.Provider>
);
}
export default NameChoose;
This is a Lazy Route component I wrote a while ago (code below).
This is what it does:
It initially render a lazyLoading = true state to show some spinner or something.
Then on useEffect it will dynamic import() a component module and set the LazyComponent state. Like setLazyComponent(module)
Then it will turn the loading to false and render <LazyComponent.default />
Note: It works as intended.
My question is:
I've tried to do the following:
Set the default property to the state. As in setLazyComponent(module.default). Since SomeComponent, which is the component that is being lazy loaded has a single default export.
Then I should be able to render just <LazyComponent/> instead of <LazyComponent.default/>
But it does not work.
And I get this error:
Why does it not work? All the rest of the code is the same. The only change I'm trying to make is the place where I access the default property.
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
const LS = {};
LS.Container_DIV = styled.div`
`;
async function lazyRender() {
const module = await import("./SomeComponent");
return new Promise((resolve) => {
resolve(module);
});
}
function LazyRoute(props) {
console.log('Rendering LazyRoute...');
const [lazyLoading,setLazyLoading] = useState(true);
const [LazyComponent,setLazyComponent] = useState(null);
useEffect(() => {
async function getLazyComponent() {
const module = await lazyRender();
setLazyComponent(module);
setLazyLoading(false);
}
getLazyComponent();
},[]);
return(
lazyLoading ?
<div>I am Lazy Loading....</div>
: <LazyComponent.default {...props}/>
);
}
export default React.memo(LazyRoute);
I create a context and a provider as below. As you can see, I use useState() within my provider (for state) along with functions (all passed within an object as the value prop, allows for easy destructuring whatever I need in child components).
import React, { useState, createContext } from "react";
const CountContext = createContext(null);
export const CountProvider = ({ children }) => {
const [count, setCount] = useState(0);
const incrementCount = () => {
setCount(count + 1);
};
const decrementCount = () => {
setCount(count - 1);
};
return (
<CountContext.Provider value={{ count, incrementCount, decrementCount }}>
{children}
</CountContext.Provider>
);
};
export default CountContext;
I wrap my app within such a provider(s) at a higher location such as at index.js.
And consume the state using useContext() as below.
import React, { useContext } from "react";
import CountContext from "../contexts/CountContext";
import Incrementer from "./Incrementer";
import Decrementer from "./Decrementer";
const Counter = () => {
const { count } = useContext(CountContext);
return (
<div className="counter">
<div className="count">{count}</div>
<div className="controls">
<Decrementer />
<Incrementer />
</div>
</div>
);
};
export default Counter;
Everything is working just fine, and I find it easier to maintain things this way as compared to some of the other methods of (shared) state management.
CodeSandbox: https://codesandbox.io/s/react-usecontext-simplified-consumption-hhfz6
I am wondering if there is a fault or flaw here that I haven't noticed yet?
One of the key differences with other state management tools like Redux is performance.
Any child that uses a Context needs to be nested inside the ContextProvider component. Every time the ContextProvider state changes it will render, and all its (non-memoized) children will render too.
In contrast, when using Redux we connect each Component to the store, so each component will render only if the part of the state it is connect to changes.