I am building an app with React using Remix, fly.io for deployment. I have a custom React hook useCountdown
that has the following code:
import { useEffect, useState } from 'react';
const useCountdown = (targetSeconds) => {
const countDownSeconds = targetSeconds
const [countDown, setCountDown] = useState(countDownSeconds);
useEffect(() => {
const interval = setInterval(() => {
setCountDown(countDownSeconds);
return () => clearInterval(interval);
}, [countDownSeconds]);
return getReturnValues(countDown);
}, [])
};
const getReturnValues = (countDown) => {
const seconds = Math.floor((countDown % (1000 * 60)) / 1000);
return [seconds];
}
export { useCountdown }
The DateTimeDisplay
component has the following code and is a component dependency of the hook:
import React from 'react';
const DateTimeDisplay = ({ value, type, isDanger }) => {
return (
<div className={isDanger ? 'countdown danger' : 'countdown'}>
<p>{value}</p>
<span>{type}</span>
</div>
);
};
export default DateTimeDisplay;
Finally, I have a CountdownTimer
component that has the following code:
import React from 'react';
import DateTimeDisplay from './DateTimeDisplay';
import ExpiredNotice from './ExpiredNotice'
import { useCountdown } from '../hooks/useCountdown';
const ShowCounter = ({ seconds }) => {
return (
<div className="show-counter">
<DateTimeDisplay value={seconds} type={'seconds'} isDanger={false} />
</div>
);
};
const CountdownTimer = ({ targetSeconds }) => {
const [seconds] = useCountdown(targetSeconds);
if (seconds <= 0) {
return <ExpiredNotice />;
} else {
return (
<ShowCounter
seconds={seconds}
/>
);
}
};
export default CountdownTimer;
Upon trying to utilize the useCountdown()
hook, I get the following error:
TypeError: useCountdown is not a function or its return value is not iterable
at CountdownTimer (/Users/tduke/Desktop/dev/drawesome/app/components/CountdownTimer.jsx:17:23)
at processChild (/Users/tduke/Desktop/dev/drawesome/node_modules/react-dom/cjs/react-dom-server.node.development.js:3353:14)
at resolve (/Users/tduke/Desktop/dev/drawesome/node_modules/react-dom/cjs/react-dom-server.node.development.js:3270:5)
at ReactDOMServerRenderer.render (/Users/tduke/Desktop/dev/drawesome/node_modules/react-dom/cjs/react-dom-server.node.development.js:3753:22)
at ReactDOMServerRenderer.read (/Users/tduke/Desktop/dev/drawesome/node_modules/react-dom/cjs/react-dom-server.node.development.js:3690:29)
at renderToString (/Users/tduke/Desktop/dev/drawesome/node_modules/react-dom/cjs/react-dom-server.node.development.js:4298:27)
at handleRequest (/Users/tduke/Desktop/dev/drawesome/app/entry.server.jsx:10:16)
at handleDocumentRequest (/Users/tduke/Desktop/dev/drawesome/node_modules/@remix-run/server-runtime/server.js:400:18)
at requestHandler (/Users/tduke/Desktop/dev/drawesome/node_modules/@remix-run/server-runtime/server.js:49:18)
at /Users/tduke/Desktop/dev/drawesome/node_modules/@remix-run/express/server.js:39:22
The line in question:
const [seconds] = useCountdown(targetSeconds);
Can someone explain to me this error, and what it exactly is telling me so I understand this error in it's entirety, and what the cause is in this instance?
How do I fix it?
CodePudding user response:
useCountdown
does not have a return statement, so it's implicitly returning undefined
. Then when you try to destructure undefined
, you get that error because array destructuring only works on arrays (or other iterables, which is why the error mentions "iterable"s, not arrays)
You did put a return statement inside your useEffect, but returning something in a useEffect is for cleaning up the effect. It won't cause useCountdown
to return anything. To fix this, move your return statement to the body of useCountdown
, and move the effect cleanup to be the return from the effect:
const useCountdown = (targetSeconds) => {
const countDownSeconds = targetSeconds
const [countDown, setCountDown] = useState(countDownSeconds);
useEffect(() => {
const interval = setInterval(() => {
setCountDown(countDownSeconds);
}, [countDownSeconds]);
return () => clearInterval(interval);
}, [])
return getReturnValues(countDown);
};