I'm trying to create a hook, but I'm not sure where I've gone wrong conceptually, as it is unfortunately not working. I've written up a test example to recreate my problems - I'm unable to get isCalculating
updates from my Page. Many thanks in advance for your help.
useTest.ts
import { useEffect, useState } from 'react'
const TEST_LENGTH = 100 * 10000000
const TEST_CRITERIA = 99 * 10000000
const useTest = () => {
const [isCalculating, setIsCalculating] = useState(false)
const [result, setResult] = useState(0)
useEffect(() => {
setIsCalculating(false)
}, [result])
const calculate = () => {
setIsCalculating(true)
for (let i = 0; i < TEST_LENGTH; i++) {
if (i >= TEST_CRITERIA) {
setResult(i)
break
}
}
}
const reset = () => {
setResult(0)
}
return { isCalculating, result, calculate, reset }
}
export default useTest
Test.tsx
import { Box, Button, Container, Text } from '@chakra-ui/react'
import { useTest } from '../helpers'
export default function Test() {
const { isCalculating, result, calculate, reset } = useTest()
return (
<Container>
<Box>
<Text>Result: {result}</Text>
{isCalculating ? <Text>is calculating...</Text> : null}
<Button
onClick={() => {
result === 0 ? calculate() : reset()
}}>
<Text>{result === 0 ? 'Calculate' : 'Reset'}</Text>
</Button>
</Box>
</Container>
)
}
What I'm seeing is isCalculating
updating in the hook only after the for loop calculation has finished, which for me is unexpected behavior. Any fixes to this?
What I've tried
Tried to mimic setState callback with useEffect in useTest
import { useEffect, useState } from 'react'
const TEST_LENGTH = 100 * 10000000
const TEST_CRITERIA = 99 * 10000000
const useTest = () => {
const [isCalculating, setIsCalculating] = useState(false)
const [result, setResult] = useState(0)
useEffect(() => {
if (isCalculating) {
for (let i = 0; i < TEST_LENGTH; i++) {
if (i >= TEST_CRITERIA) {
setResult(i)
break
}
}
}
}, [isCalculating])
const calculate = () => {
setIsCalculating(true)
}
useEffect(() => {
setIsCalculating(false)
}, [result])
const reset = () => {
setResult(0)
}
return { isCalculating, result, calculate, reset }
}
export default useTest
Unfortunately (kind of expected) it still doesn't work.
CodeSandbox link: here
As you can see, the I've set up an alert and some text to show on screen when isCalculating
is true, unfortunately they both don't show until the calculation has completed.