score:8
the reason why you did not get updated state is because you called it inside useeffect(() => {}, []) which is only called just once.
useeffect(() => {}, []) works just like componentdidmount().
when gamestart function is called, gameplaytime is 100, and inside gamestart, it uses the same value however the timer works and the actual gameplaytime is changed. in this case, you should monitor the change of gameplaytime using useeffect.
...
useeffect(() => {
if (gameplaytime % targetshowtime === 0) {
const random = (math.floor(math.random() * 10000) % wp("70")) + wp("10");
const targetposition = { x: random, y: hp("90") };
const spininfodata = getspinarray()[math.floor(math.random() * 10) % 4];
newspinshow(targetposition, spininfodata, spinspeed);
}
}, [gameplaytime]);
const gamestart = () => {
gamestartinternal = setinterval(() => {
setgameplaytime(t => t-1);
}, 1000);
};
...
score:4
you shouldn't use setinterval with hooks. take a look at what dan abramov, one of the maintainers of react.js, said regarding an alternative on his blog: https://overreacted.io/making-setinterval-declarative-with-react-hooks/
score:5
https://overreacted.io/making-setinterval-declarative-with-react-hooks/
dan abramov article explain well how to works with hooks, state, and the setinterval() type of api!
dan abramov! is one of the react maintaning team! so known and i pesonally love him!
quick explanation
the problem is the problem of how to access state with a useeffect() that execute only once (first render)!
the short answer is: by the use of refs (useref)! and another useeffect() that run again when update is necessary! or at each render!
let me explain! and check the dan abramov solution! and you'll get better the statement above at the end! with a second example that is not about setinterval()!
=>
useeffect() either run once only, or run in each render! or when the dependency update (when provided)!
accessing state can be possible only through a useeffect() that run and render each relevant time!
or through setstate((state/*here the state*/) => <newstateexpression>)
but if you want to access the state inside useeffect() => rerun is necessary! meaning passing and executing the new callback!
that doesn't work well with setinterval! if you set it each time! the counter get reset! leading to no execution if the component is re-rendering fast!
if you render only once! the state is not updated! as the first run, run a one callback! and make a closure! the state is fixed! useeffect(() => { <run once, state will stay the same> setinterval(() => { <state fixed> }) }, [])
.
for all such kind of situation! we need to use useref! (refs)!
save to it a callback that hold the state! from a useeffect() that rerender each time! or by saving the state value itself in the ref! depending on the usage!
dan abramov solution for setinterval (simple and clean)
that's what you are looking for!
useinteval hook (by dan abramov)
import react, { usestate, useeffect, useref } from 'react';
function useinterval(callback, delay) {
const savedcallback = useref();
// remember the latest callback.
useeffect(() => {
savedcallback.current = callback;
}, [callback]);
// set up the interval.
useeffect(() => {
function tick() {
savedcallback.current();
}
if (delay !== null) {
let id = setinterval(tick, delay);
return () => clearinterval(id);
}
}, [delay]);
}
usage
import react, { usestate, useeffect, useref } from 'react';
function counter() {
let [count, setcount] = usestate(0);
useinterval(() => {
// your custom logic here
setcount(count + 1);
}, 1000);
return <h1>{count}</h1>;
}
we can see how he kept saving the new callback at each re-render! a callback that contain the new state!
to use ! it's a clean simple hook! that's a beauty!
make sure to read dan article! as he explained and tackled a lot of things!
setstate()
dan abramov mentioned this in his article!
if we need to set the state! within a setinteral! one can use simply setstate() with the callback version!
usestate(() => {
setinterval(() => {
setstate((state/*we have the latest state*/) => {
// read and use state
return <newstateexpression>;
})
}, 1000);
}, []) // run only once
we can even use that! even when we are not setting state! possible! not good though! we just return the same state value!
setstate((state) => {
// run right away!
// access latest state
return state; // same value (state didn't change)
});
however this will make different react internal code part to run (1,2,3), and checks! which end by bailing out from re-rendering! just fun to know!
we use this only for when we are updating the state! if not ! then we need to use refs!
another example: usestate() with getter version
to show case the how to work with refs and state access! let's go for another example! here another pattern! passing state in callbacks!
import react from 'react';
function usestate(defaultval) {
// getting the state
const [state, setstate] = react.usestate(defaultvalue);
// state holding ref
const stateref = react.useref();
stateref.current = state; // setting directly here!
// because we need to return things at the end of the hook execution
// not an effect
// getter
function getstate() {
// returning the ref (not the state directly)
// so getter can be used any where!
return stateref.current;
}
return [state, setstate, getstate];
}
the example is of the same category! but here no effect!
however we can use the above hook to access state in the hook simply as bellow!
const [state, usestate, getstate] = usestate(); // our version! not react
// ref is already uptated by this call
react.useeffect(() => {
setinteval(() => {
const state = getstate();
// do what you want with the state!
// it works because of the ref! get state return a value to the same ref!
// which is already updated
}, 1000)
}, []); // running only once
for setinterval()! the good solution is dan abramov hook! making a strong custom hook for a thing is the cool thing to do! this second example is more to showcase the usage and importance of refs, in such state access need or problem!
it's simple! we can always make a custom hook! use refs! and update the state in ref! or a callback that hold the new state! depending on usage! we set the ref on the render (directly in the custom hook [the block execute in render()])! or in a useeffect()! that re-run at each render or depending on the dependencies!
note about useeffect() and refs setting
to note about useeffect()
useeffect => useeffect runs asynchronously and after a render is painted to the screen.
- you cause a render somehow (change state, or the parent re-renders)
- react renders your component (calls it)
- the screen is visually updated
- then useeffect runs
very important of a thing! useeffect() run after render() finish and the screen is visually updated! it run last! you should be aware!
generally however! effects should be run on useeffect()! and so any custom hook will be ok! as it's useeffect() will run after painting and before any other in render useeffect()! if not! as like needing to run something in the render directly! then you should just pass the state directly! some people may pass a callback! imagine some logic component! and a getstate callback passed to it! not a good practice!
and if you do something somewhere of some of such sense! and talking about ref! make sure the refs are updated right! and before!
but generally you'll never have a problem! if you do then it's a smell! the way you are trying to go with is high probably not the right good way!
in the whole i hope that gave you a good sense!
score:7
you're creating a closure because gamestart()
"captures" the value of gameplaytime
once when the useeffect hook runs and never updates after that.
to get around this, you must use the functional update pattern of react hook state updating. instead of passing a new value directly to setgameplaytime()
, you pass it a function and that function receives the old state value when it executes and returns a new value to update with. e.g.:
setgameplaytime((oldvalue) => {
const somenewvalue = oldvalue + 1;
return somenewvalue;
});
try this (essentially just wrapping the contents of your setinterval function with a functional state update):
const [gameplaytime, setgameplaytime] = react.usestate(100);
let targetshowtime = 3;
// call function
react.useeffect(() => {
gamestart();
}, []);
const gamestart = () => {
gamestartinternal = setinterval(() => {
setgameplaytime((oldgameplaytime) => {
console.log(oldgameplaytime); // will print previous gameplaytime value
if (oldgameplaytime % targetshowtime === 0) {
const random = (math.floor(math.random() * 10000) % wp("70")) + wp("10");
const targetposition = { x: random, y: hp("90") };
const spininfodata = getspinarray()[math.floor(math.random() * 10) % 4];
newspinshow(targetposition, spininfodata, spinspeed);
}
return oldgameplaytime - 1;
});
}, 1000);
};
Source: stackoverflow.com
Related Query
- Can not update state inside setInterval in react hook
- State not updating when using React state hook within setInterval
- How to properly update an array inside a react hook state
- React useState() hook does not update state when child.shouldComponentUpdate() returns false
- setState does not update state immediately inside setInterval
- React testing library: An update inside a test was not wrapped in act(...) & Can't perform a React state update on an unmounted component
- React update state hook on functional component does not allow dot notation
- React does not re-render all componenets on state update in a custom hook
- React cannot set state inside useEffect does not update state in the current cycle but updates state in the next cycle. What could be causing this?
- useState React Hook set method does not update state immediately in onChange()
- Can not get latest state in React hook | Stale Closure Issue
- React hook state - does not update component
- React Hooks: Instantiating state hooks on validation Error: Invalid hook call. Hooks can only be called inside of the body of a function component
- React state update error whenever i open someone's image, and image not redering too. How can I fix this error
- React state not updating inside setInterval
- React State is not getting update before assertion even acting inside act function
- Why useState in React Hook not update state
- How can I re-trigger a custom hook inside my react component, when its states have not changed?
- how can i add setinterval function inside React new array state
- State does not update React Hook
- Can I set state inside a useEffect hook
- UI not re-rendering on state update using React Hooks and form submission
- how to update multiple state at once using react hook react.js
- Can not pass state with react router dom v6 beta, state is null
- React does not refresh after an update on the state (an array of objects)
- React not re-rendering after array state update
- React update state if image not found.
- React Hook useCallback not updating State value
- React js changing state does not update component
- Access old state to compare with new state inside useEffect react hook with custom hooks usePrevious
More Query from same tag
- react-select dropdown not showing cursor
- How to NOT delete existing translations with "react-intl-translations-manager"?
- Audio to blob and POST to cloudinary issue
- How to enable/add anchor tag to the string in ReactJS?
- react meteor data container doesn't update child when props change
- Passing HTML attributes from a DeepReadonly object in Typescript
- Optimise canvas drawing of a circle
- Summing up prices of user's cart from 2 arrays
- How do I fetch from swapi from react app?
- Uncaught TypeError: Cannot call method 'checkDomStatus' of undefine
- How to store an object in component's state?
- How to set the state of a component with the information obtained from a promise to avoid memory leaks in react
- How to use state in anonymous method using react in component
- dispatch: Dispatch<AnyAction> why sometime you have to precise the Action?
- Improve React-Context structure
- How do I render json data in the javascript function using map - Reactjs
- How to make a dynamic watch()/usewatch() with react-hook-forms
- How to set the initial state in React based on a Rx.ReplaySubject model
- How to apply onClick on tr except one td?
- How to get the current full URL in Next.js/Typescript component?
- resetForm() on Formik doesn't clear all fields
- How can I check the return value of dispatch in redux hook
- How to disable some options in "Select" component of Material-UI like in "Autocomplete"?
- react router get props in parent
- How to disable HTML5 validation in React using formsy-react?
- high order component throws an invalid react element error (reactjs)
- How to compare array and render elements in react
- setState after loading an array from firebase
- REACT NATIVE - this.setState doesn't work inside onChangeText
- How do I import pre built in components from a cdn js?