useEffect() infinitely runs for some reason - javascript

So I'm currently trying to learn react and as practice I was just trying to build a hacker news site using the hacker new API. But, I ran into a issue. For some reason it is currently infinitely looping. I debugged it and found that it has something to do with the useEffect() hook. I tried the solution in this post but it didn't seam to work(I think I probably did it wrong though).
My Code:
const [maindata, setmaindata] = useState("");
useEffect(() => {
axios
.get("https://hacker-news.firebaseio.com/v0/user/jl.json?print=pretty")
.then((repo) => {
const output = [];
// repo.data["submitted"].length
for (let x = 0; x < 30; x++) {
axios
.get(
"https://hacker-news.firebaseio.com/v0/item/" +
repo.data["submitted"][x] +
".json?print=pretty"
)
.then((titledata) => {
//console.log(titledata.data["text"]);
output.push(titledata.data["text"]);
});
}
});
setmaindata(output);
});
I also tried replacing:
}
});
setmaindata(output);
});
With:
}
});
}, [output});
But that didn't seem to work

If you don't pass the dependency array to useEffect, useEffect runs on every render.
By pass empty array([]) as dependency, useEffect runs once when component is mounted.
Ex:
useEffect(() => {
... // your code
}, [])

You should add dependency to useEffect because if you don't add any dependency, this method infinitely runs.
Just implement at the end of method [].
In addition, take care with setMainData because you call it outside of axis request.
Final code could be this:
const [maindata, setmaindata] = useState("");
useEffect(() => {
axios
.get("https://hacker-news.firebaseio.com/v0/user/jl.json?print=pretty")
.then((repo) => {
const output = [];
// repo.data["submitted"].length
for (let x = 0; x < 30; x++) {
axios
.get(
"https://hacker-news.firebaseio.com/v0/item/" +
repo.data["submitted"][x] +
".json?print=pretty"
)
.then((titledata) => {
//console.log(titledata.data["text"]);
output.push(titledata.data["text"]);
// here you have output array with the push action that you did in previous line
setmaindata(output);
});
}
});
}, [dependency]);
Change dependency with your variable that you want to use when this value changes this useEffect will be called

Related

How react hooks are updating state

I have a long process that updates the state. I want to show red background when it's running and blue when it's done.
const MapBuilder = (props) => {
const [backgroundColor, setBackgroundColor] = useState(false);
const [fancyResult, setFancyResult] = useState(null);
console.log(`stop 1 backgroundColor ${backgroundColor} fancyResult ${fancyResult}`)
const veryHardWork = () => {
setBackgroundColor("red");
console.log(`stop 2 backgroundColor ${backgroundColor} fancyResult ${fancyResult}`)
for (let i = 0; i < 1000; i++) {
for (let j = 0; j < 1000; j++) {
console.log("So hard")
}
}
setFancyResult("done")
console.log(`stop 3 backgroundColor ${backgroundColor} fancyResult ${fancyResult}`)
setBackgroundColor("blue")
console.log(`stop 4 backgroundColor ${backgroundColor} fancyResult ${fancyResult}`)
}
return (<div style={{background: backgroundColor}}>
<button className="btn btn-primary" onClick={veryHardWork}></button>
</div>)
}
Here is an output of such run
stop 1 backgroundColor false fancyResult null
MapBuilder.js:13 stop 2 backgroundColor false fancyResult null
10000MapBuilder.js:16 So hard
MapBuilder.js:20 stop 3 backgroundColor false fancyResult null
MapBuilder.js:22 stop 4 backgroundColor false fancyResult null
MapBuilder.js:10 stop 1 backgroundColor blue fancyResult done
I understand from this that the state change only happens after the method veryHardWork is finished. In my real project, I actually want to show a spinner the question is how can I do it if the state is only changed at the end of the method.
I think some clarification needs to be added. In reality, I allow the user to choose a file after the user chooses the file it is loaded and some heavy processing is performed on files data while the processing is running I want to show a spinner no Asyn work involved.
Some of the answers sugested to use useEffect and moving it to a promise I tryied both but it did not help here is a different take on it which also did not work
const MapBuilder = (props) => {
const [backgroundColor, setBackgroundColor] = useState(false);
const [fancyResult, setFancyResult] = useState(null);
const [startProcessing, setStartProcessing] = useState(null);
useEffect(() => {
let myFunc = async () => {
if (startProcessing) {
setBackgroundColor("red");
await hardWork();
setBackgroundColor("blue");
setStartProcessing(false);
}
}
myFunc();
}, [startProcessing])
const hardWork = () => {
return new Promise((resolve)=> {
for (let i = 0; i < 500; i++) {
for (let j = 0; j < 100; j++) {
console.log("So hard")
}
}
setFancyResult("sdsadsad")
resolve("dfsdfds")
})
}
return (<div style={{background: backgroundColor}}>
<button className="btn btn-primary" onClick={() => setStartProcessing(true)}></button>
</div>)
}
export default MapBuilder;
The problem with the approach is that the heavy calculation is happening at the main loop with the same priority. The red color change will not ever cause any changes until all things at the event handler have been finished.
With Reach 18 you can make your heavy calculation to be with lower priority and let the UI changes happen with normal priority. You can make this happen with minor change on your code base:
const veryHardWork = () => {
setBackgroundColor("red");
// Set heavy calculation to happen with lower priority here...
startTransition(() => {
console.log(`stop 2 backgroundColor ${backgroundColor} fancyResult ${fancyResult}`)
for (let i = 0; i < 1000; i++) {
for (let j = 0; j < 1000; j++) {
console.log("So hard")
}
}
setFancyResult("done")
setBackgroundColor("blue")
}
}
So I've made you a more real world example as the code you posted doesn't look like what you're actually wanting to achieve.
The scenario to my understanding is you want to preform some setup actions to get your state / data ready before showing it to the user.
cool, so first we will need some state to keep track of when we're ready to show content to the user lets call it isLoading. This will be a boolean that we can use to conditionally return either a loading spinner, or our content.
next we need some state to keep hold of our data, lets call this one content.
each state will be created from React.useState which can be imported with import { useState } from 'react';. We will then create variables in the following format:
const [state, setState] = useState(null);
nice, so now lets do somthing when the component mounts, for this we will use React.useEffect this hook can be used to tap into the lifecycle of a component.
inside our useEffect block we will preform our set up. In this case I'll say it's an async function that get some data from an API and then sets it to state.
lastly we will use our isLoading state to decide when we're ready to show the user something more interesting than a spinner.
All together we get something like this:
import { useState, useEffect } from 'react';
const MyComponent = () => {
// create some state to manage when what is shown
const [isLoading, setIsLoading] = useState(true);
// create some state to manage content
const [content, setContent] = useState(null);
// when the component is mounted preform some setup actions
useEffect(() => {
const setup = async () => {
// do some setup actions, like fetching from an API
const result = await fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(r => r.json());
// update our state that manages content
setContent(result);
// when we are happy everything is ready show the user the content
setIsLoading(false);
};
// run our setup function
setup();
}, [ ]);
// if we are not yet ready to show the user data, show a loading message
if (isLoading) {
return (
<div>
<p>spinner goes in this div</p>
</div>
)
}
// when we are ready to show the user data is will be shown in this return statement
return (
<div>
<p>this div will show when the `isLoading` state is true and do something with the content state is wanted</p>
</div>
)
}
I believe you'll find this more useful than the example you provided
You already control state of fancyResult,
or you can use showSpinner state for only reason to show spinner
You can use for long progress Promise [Link] And Async/Await [Link]
const veryHardWork = async () => {
setBackgroundColor("red");
const awaiting = await new Promise((resolve, reject) => {
for (let i = 0; i < 1000; i++) {
for (let j = 0; j < 1000; j++) {
resolve(console.log("So hard"));
}
}
})
// After Finished Awating Hardwork
setFancyResult("done");
setBackgroundColor("blue") ;
}
return (
<div style={{background: fancyResult === 'done' ? 'blue': 'red'}}>
<button className="btn btn-primary" onClick={veryHardWork}></button>
{ fancyResult === 'done' && 'Show Spinner' }
</div>
)
Try this:
import { useState, useEffect } from "react";
import { flushSync } from "react-dom";
const MapBuilder = (props) => {
const [backgroundColor, setBackgroundColor] = useState(false);
const [fancyResult, setFancyResult] = useState(null);
// this will only be called on the first mount
useEffect(() => {
console.log(
`backgroundColor ${backgroundColor} fancyResult ${fancyResult}`
);
}, [backgroundColor, fancyResult]);
const veryHardWork = () => {
setBackgroundColor("red");
setTimeout(() => {
for (let i = 0; i < 1000; i++) {
for (let j = 0; j < 1000; j++) {
for (let k = 0; k < 1000; k++) {
// console.log("So hard");
}
}
}
setFancyResult("done");
// flushSync(() => setFancyResult("done"));
console.log(
`inside closure - OUTDATED: backgroundColor ${backgroundColor} fancyResult ${fancyResult}`
);
setBackgroundColor("blue");
}, 0);
};
return (
<div style={{ background: backgroundColor }}>
<button className="btn btn-primary" onClick={veryHardWork}>
Work!
</button>
</div>
);
};
export default MapBuilder;
CodeSandbox
Explanation:
Unblocking the UI thread
In order for the color to change to red, the UI thread must be freed up to
make the state changes (set background color to red) and
do the re-render.
One way to achieve this is by using setTimeout. This puts a function on a queue to be run later, allowing the UI thread to finish the above 2 tasks before tackling the actual work. You should note though, this doesn’t actually run your work on a new thread, so once the work starts getting done, the UI will be unresponsive until the work is done. Consider using a Web Worker to solve this in the future.
Logging the current state
The other thing to understand about React is that every time a re-render occurs, the entire function ('MapBuilder’ in this case) is re-run. This means that your ‘stop 1’ message will be displayed every re-render, and therefore every time the state changes.
Additionally, logging the state from within veryHardWork will log the state when the function was defined. This means that the value will be outdated, i.e. stale. This is because of a functional concept called closures. From Wikipedia “Unlike a plain function, a closure allows the function to access those captured variables through the closure's copies of their values or references, even when the function is invoked outside their scope.”
So how should we log the current state when it is changed? By using the useEffect hook. This function will be re-run whenever any of the dependencies change ([backgroundColor, fancyResult] in this case).
Console.log undefined behavior
Another thing to note is that many console.logs should not be used as the ‘work’. The rendering of the log will happen asynchronously, so ‘firing’ the logs will be much quicker than they will actually show up. This leads the observer watching the console to think that the ‘red’ stage has been skipped. Instead, we can just loop more times, or do some math in the loop, etc (which is closer to what your actual synchronous work will be anyway). In fact, console.log seems to be quite unpredictable, as noted here.
Automatic Batching
You might be wondering why “done” and “blue” show up as a single state update (i.e. stop 3 and 4 happen at the same time). This is because of automatic batching. As a performance optimization, react attempts to ‘batch’ state changes to prevent additional re-renders. To prevent this behavior, you can uncomment line 27 flushSync(() => setFancyResult("done”)). This is not necessary for this use-case, as the batching is appropriate here, but it’s helpful to understand what’s going on.

Trying to use useRef to run a function on a generated item in React/Remix/Prisma

I've gone through multiple useRef/useEffect instructions but I just can't seem to make it work here.
The code workflow here is: Remix/React, get data from database, display data, turn data into a ticker that can be updated
If anyone could point out any glaring errors they see in this code as to why the useEffect hook isn't firing, or why the useRef hook can never find the {listRef} within the <ul>, I would love to know.
import { Links, redirect, useLoaderData, Outlet } from 'remix'
import { db } from '~/utils/db.server'
import { getUser } from '~/utils/session.server'
import { ReactSortable } from "react-sortablejs"
import { useState, useRef, useEffect } from 'react'
import tickerStylesUrl from '~/styles/tickerDisplay.css'
export const links = () => [{ rel: 'stylesheet', href: tickerStylesUrl }]
export const loader = async ({ request, params }) => {
const user = await getUser(request)
const ticker = await db.ticker.findUnique({
where: { id: params.tickerId },
include: {
headlines: true,
},
})
if (!ticker) throw new Error('Ticker not found')
const data = { ticker, user }
return data
}
export const action = async ({ request, params }) => {
}
// The ticker function displays the items without styling, so it finds the database perfectly and can get the data
function displayTicker() {
const { ticker, user } = useLoaderData()
const headlines = ticker.headlines
const tickerParentStyle = {
width: "1920px",
height: "1080px",
position: "relative",
backgroundColor: "black"
}
const tickerStyle = {
position: "absolute",
padding: "0",
bottom: "0",
color: `${ticker.fontColor}`,
backgroundColor: `${ticker.backgroundColor}`,
fontFamily: `${ticker.font}`,
fontSize: "2em",
}
const tickerHeadlineStyle = {
margin: "auto",
height: "50%",
}
console.log("Headlines: " + headlines)
// So begins the found ticker code I had hoped to integrate
// Source: https://www.w3docs.com/tools/code-editor/2123
function scrollTicker() {
const marquee = listRef.current.querySelectorAll('.tickerHeadlines');
let speed = 4;
let lastScrollPos = 0;
let timer;
marquee.forEach(function (el) {
const container = el.querySelector('.headlineItem');
const content = el.querySelector('.headlineItem > *');
//Get total width
const elWidth = content.offsetWidth;
//Duplicate content
let clone = content.cloneNode(true);
container.appendChild(clone);
let progress = 1;
function loop() {
progress = progress - speed;
if (progress <= elWidth * -1) {
progress = 0;
}
container.style.transform = 'translateX(' + progress + 'px)';
container.style.transform += 'skewX(' + speed * 0.4 + 'deg)';
window.requestAnimationFrame(loop);
}
loop();
});
window.addEventListener('scroll', function () {
const maxScrollValue = 12;
const newScrollPos = window.scrollY;
let scrollValue = newScrollPos - lastScrollPos;
if (scrollValue > maxScrollValue) scrollValue = maxScrollValue;
else if (scrollValue < -maxScrollValue) scrollValue = -maxScrollValue;
speed = scrollValue;
clearTimeout(timer);
timer = setTimeout(handleSpeedClear, 10);
});
function handleSpeedClear() {
speed = 4;
}
}
const listRef = useRef()
console.log("listRef: " + JSON.stringify(listRef))
// This console appears everytime, but is always empty, presumably because DOM has just rendered
useEffect(() => {
console.log("useEffect fired")
// This console NEVER fires, sadly. I thought this would happen ONCE rendered
}, [listRef]);
return (
<>
<Links />
<div style={tickerParentStyle}>
<div style={tickerStyle}>
<div key={ticker.id} style={tickerHeadlineStyle} class="tickerWrapper">
// HERE IS THE TARGET UL
<ul className="tickerHeadlines" ref={listRef} style={{ margin: "10px 0 10px 0" }} >
{/* Hoping to map through the ticker items here, and have them displayed in a list, which would then be manipulated by the useRef/useEffect hook */}
{headlines.map((headline) => (
<>
<li class="headlineItem" key={headline.id}>
<span>
{headline.content} {ticker.seperator}
</span>
</li>
</>
))}
{scrollTicker()}
</ul>
</div>
</div>
</div>
</>
)
}
export default displayTicker
As always, any help is appreciated.
useRef is a hook that is used to access DOM elements, manipulating the DOM directly in a React application breaks the whole point of declarative programming. It is not at all advised to manipulate DOM directly using any dom objects and methods such as document. Coming to the useEffect hook, the useEffect hook runs conditionally depending on what's supplied in the dependency array, if none, the hook runs only once after the component finishes mounting. So you should be careful regarding what needs to be passed to the useEffect dependency array. Considering your case, when you pass listRef, the useEffect runs only when there is a change in the object and not it's properties, because objects are non-primitive, any changes in the property is not treated as a change in the object, and its merely an object property mutation that doesn't cause re-render. To steer clear, you should be sure of, when exactly you want it to be invoked, as you mentioned, you'd want it to run right after the data has rendered, you could instead use headlines in your dependency array.
Change the dependency array to include headlines.
useEffect(() => {
console.log("useEffect fired")
// This console NEVER fires, sadly. I thought this would happen ONCE rendered
}, [headlines]);
Alternatively, you could also leave it empty, making it run only once after the component has mounted.
useEffect(() => {
console.log("useEffect fired")
// This console NEVER fires, sadly. I thought this would happen ONCE rendered
}, []);
A caveat, the former snippet would run every time there's a change in headlines, and the latter would run only once no matter what changes.
So, depending on your use case, you might want to choose the one that best suits your needs.
There are a couple of things to code make code better:
initiate ref with 'null' value
call your 'scrollTicker' function inside useEffect Hook.
always remove listeners when component demount. Follow https://reactjs.org/docs/hooks-reference.html#useeffect for more details
you can use useEffect hook like this:
useEffect(() => {
// use your ref here.
return () => {
// Remove linteners
};
});

Function A depends on previous function to update the state, but Function A still tries to render before the update

An Example I have linked below, that shows the problem I have.
My Problem
I have these two functions
const updatedDoc = checkForHeadings(stoneCtx, documentCtx); // returns object
documentCtx.setUserDocument(updatedDoc); // uses object to update state
and
convertUserDocument(stoneCtx, documentCtx.userDocument);
// uses State for further usage
The Problem I have is, that convertUserDocument runs with an empty state and throws an error and then runs again with the updated state. Since it already throws an error, I cannot continue to work with it.
I have tried several different approaches.
What I tried
In the beginning my code looked like this
checkForHeadings(stoneCtx, documentCtx);
// updated the state witch each new key:value inside the function
convertUserDocument(stoneCtx, documentCtx.userDocument);
// then this function was run; Error
Then I tried the version I had above, to first put everything into an object and update the state only once.
HavingconvertUserDocument be a callback inside of checkForHeadings, but that ran it that many times a matching key was found.
My current try was to put the both functions in seperate useEffects, one for inital render and one for the next render.
const isFirstRender = useRef(true);
let init = 0;
useEffect(() => {
init++;
console.log('Initial Render Number ' + init);
console.log(documentCtx);
const updatedDoc = checkForHeadings(stoneCtx.stoneContext, documentCtx);
documentCtx.setUserDocument(updatedDoc);
console.log(updatedDoc);
console.log(documentCtx);
isFirstRender.current = false; // toggle flag after first render/mounting
console.log('Initial End Render Number ' + init);
}, []);
let update = 0;
useEffect(() => {
update++;
console.log('Update Render Number ' + update);
if (!isFirstRender.current) {
console.log('First Render has happened.');
convertUserDocument(stoneCtx.stoneContext, documentCtx.userDocument);
}
console.log('Update End Render Number ' + update);
}, [documentCtx]);
The interesting part with this was to see the difference between Codesandbox and my local development.
On Codesandbox Intial Render was called twice, but each time the counter didn't go up, it stayed at 1. On the other hand, on my local dev server, Initial Render was called only once.
On both version the second useEffect was called twice, but here also the counter didn't go up to 2, and stayed at 1.
Codesandbox:
Local Dev Server:
Short example of that:
let counter = 0;
useEffect(()=> {
counter++;
// this should only run once, but it does twice in the sandbox.
// but the counter is not going up to 2, but stays at 1
},[])
The same happens with the second useEffect, but on the second I get different results, but the counter stays at 1.
I was told this is due to a Stale Cloruse, but doesn't explain why the important bits don't work properly.
I got inspiration from here, to skip the initial render: https://stackoverflow.com/a/61612292/14103981
Code
Here is the Sandbox with the Problem displayed: https://codesandbox.io/s/nameless-wood-34ni5?file=/src/TextEditor.js
I have also create it on Stackblitz: https://react-v6wzqv.stackblitz.io
The error happens in this function:
function orderDocument(structure, doc, ordered) {
structure.forEach((el) => {
console.log(el.id);
console.log(doc);
// ordered.push(doc[el.id].headingHtml);
// if (el.children?.length) {
// orderDocument(el.children, doc, ordered);
// }
});
return ordered;
}
The commented out code throws the error. I am console.loggin el.id and doc, and in the console you can see, that doc is empty and thus cannot find doc[el.id].
Someone gave me this simple example to my problem, which sums it up pretty good.
useEffect(() => {
documentCtx.setUserDocument('ANYTHING');
console.log(documentCtx.userDocument);
});
The Console:
{}
ANYTHING
You can view it here: https://stackblitz.com/edit/react-f1hwky?file=src%2FTextEditor.js
I have come to a solution to my problem.
const isFirstRender = useRef(true);
useEffect(() => {
const updatedDoc = checkForHeadings(stoneCtx.stoneContext, documentCtx);
documentCtx.setUserDocument(updatedDoc);
}, []);
useEffect(() => {
if (!isFirstRender.current) {
convertUserDocument(stoneCtx.stoneContext, documentCtx.userDocument);
} else {
isFirstRender.current = false;
}
}, [documentCtx]);
Moving isFirstRender.current = false; to an else statement actually gives me the proper results I want.
Is this the best way of achieving it, or are there better ways?

Using React To Create a Loop That Updates A Number Value

Trying to create an auto-clicker/idle game. So far the entire application works except for this loop. After the loop begins, if I update the counter, different values update in intervals. So my counter will display those different values, going back and forth between them depending on how many times I've tried to mess with the counter while its looping.
I've tried using while loops, if statements, and for loops. And for each of those loops I've tried both setInterval() and setTimeout(). They either lead to the problem above, or the browser crashing.
Here's a video of the issue:
Youtube Link
Here's the relevant code I've got currently:
const Counter = () => {
const [counter, setCounter] = useState(1);
const [minions, setMinions] = useState(0);
let minionCost = minions * 10 + 6;
let autoMinions = () => {
if (minions > 0) {
setTimeout(() => {
setCounter(minions + counter);
}, 1000);
} else {
return null;
}
};
const onClickMinion = () => {
if (counter < minionCost) {
console.log(`you don't have ${minionCost} to spend`);
} else {
setCounter(counter - minionCost);
setMinions(minions + 1);
}
};
autoMinions();
};
If you're computing state based off of a previous state, you should use functional updates.
Try passing setCounter a function that receives the previous state instead of using counter directly (do this with any of your useState hooks that depend on previous state):
setCounter(prevCounter => prevCounter + minions)

Variables Being Changed In Fetch But Unchanged Outside of Function

I have a React App and I have an App container where I want to call a fetch to get some data to pass through to components that will need that information.
I've declared variables outside of the an onload function (where my fetch is located) and assigned them different values in the fetch. They variables will change in the fetch but outside of the fetch they remain unchanged.
How come they are not staying changed and is there a way to fix this?
I've tried changed the variables declared with var instead of let and I've tried putting the function inside the const.
I've also tried putting the fetch inside of other components (like Table as seen below) but then I have to declare two states and call a fetch withint a fetch because I'm already calling another fetch there and it becomes cumbersome...
let latestRelease = 0;
let draftRelease = 0;
let doClone = false;
function onload() {
fetch(url, {
method: 'GET'
})
.then(function(response) {
return response.json();
})
.then(function(result) {
for(var i = 0; i < result.length; i++)
{
if(result[i].id > latestRelease && result[i].status === "released") {
latestRelease = result[i].id;
}
if(result[i].id > draftRelease && result[i].status === "draft") {
draftRelease = result[i].id;
}
}
if(latestRelease > draftRelease) {
doClone = true;
}
})
.catch((error) => {
console.log(error);
});
}
const App: React.FC = () => {
onload()
return (
<React.Fragment>
<CssBaseline />
<Container fixed>
<PersistentDrawerLeft/>
{console.log(latestRelease)} //displays 0
<Title/>
<Table />
</Container>
</React.Fragment>
);
}
export default App;
I'm expecting for latestRelease and draftRelease to not stay as 0 but anything greater than that but the output is just 0. With the correct values returned I'd then like to pass them as props to the components.
Many thanks!
Part of the issue is that you don't seem to be properly distinguishing between synchronous and asynchronous code. fetch is asynchronous, meaning that that code is not guaranteed to run before anything else in the file. (fetch uses JS promises to manage async data, so it helps to have a good grasp on using promises.)
In a typical React case, you want to do a few things differently. First, you want to use component state to hold on to the data, rather than just random variables (this allows React to re-render when those values change). Secondly, when you're fetching data asynchronously, you need to work out what your app should do before the fetch is complete.
Here's a very basic example showing how this could work:
import React, { useState, useEffect } from 'react'
const App = ({ url }) => {
// We'll use this variable to store an object with the details
const [releaseDetails, setReleaseDetails] = useState(null)
// When the component is loaded, we'll fetch the url (coming from the component props) and then
// run your logic.
useEffect(() => {
let latestRelease = 0;
let draftRelease = 0;
let doClone = false;
fetch(url)
.then((response) => response.json())
.then((result) => {
for(var i = 0; i < result.length; i++) {
if(result[i].id > latestRelease && result[i].status === "released") {
latestRelease = result[i].id;
}
if(result[i].id > draftRelease && result[i].status === "draft") {
draftRelease = result[i].id;
}
}
if(latestRelease > draftRelease) {
doClone = true;
}
// To make these details available to the component, we'll bundle them into an object
// and update the component's state:
setReleaseDetails({
latestRelease,
draftRelease,
doClone
})
})
.catch((error) => {
// You'd ideally want some proper error handling here
console.log(error)
});
}, []) // pass an empty array so this is only run when the component is first rendered
// Because we're getting the data asynchronously, we need to display something while we wait
if(releaseDetails === null) {
return "loading..."
}
// Once the data is available, you can then use the details when rendering. You could instead
// render a child component and pass the values as props to it.
return (
`LatestRelease: ${releaseDetails.latestRelease}`
)
}
Speaking generally, there are probably a few React and general JS concepts you'll want to make sure you have your around, particularly around state and async data fetching. Not sure how much experience you've had with it so far, but you may want to take a look at some intro tutorials (possibly like this official one) to see how much you can follow and if there's anything that jumps out as something you need to familiarise yourself with more.
can you please try with state variable ,because if state variable changes the render will call again, here your using a normal variable may be its changing but its not rendering.
Thank You.
Variable should be in the state for re rendering

Categories

Resources