I'm working in a React project, so every time I sign up a new user, it's created 2 customer ID, it's supposed to create inly one per user.
This is my code:
const ConfirmEmail = ({ handleItems, onSubmitUser }) => {
let params = useParams();
let isMounted = true;
const [loading, setLoading] = useState(true);
useCallback(() => {
fetchData();
}, [isMounted]);
const fetchData = async () => {
try {
if (JSON.parse(localStorage.getItem("user"))) return;
const response = await UserService.confirmEmail(params.tokenEmail);
if (response && response.data && !response.err) {
const { user, accessToken } = response.data;
localStorage.setItem("accessToken", accessToken);
if (isMounted) {
handleItems();
onSubmitUser(user);
}
}
if (isMounted) setLoading(false);
} catch (err) {
const { response } = err;
if (response?.data?.data) toast.error(response.data.data);
}
// Unmounted
return (isMounted = false);
};
You probably made a mistake when writing the code in the question, and you actually have:
useEffect(() => {
fetchData();
}, []);
Rather than:
useCallback(() => {
fetchData();
}, [])
As in the second option, the callback you define is never called.
I suspect you are only experiencing this issue in development, because React calls useEffect
twice in development when using React.StrinctMode
(quick way to verify, just remove React.StrictMode
).
You can fix this using a ref
to make sure you only send one request:
const ConfirmEmail = ({
handleItems,
onSubmitUser,
}) => {
const params = useParams();
const [loading, setLoading] = useState(true);
const confirmEmail = useCallback(() => {
try {
if (localStorage.getItem("user")) return;
const response = await UserService.confirmEmail(params.tokenEmail);
if (response && response.data) {
const { user, accessToken } = response.data;
localStorage.setItem("accessToken", accessToken);
handleItems();
onSubmitUser(user);
}
} catch (err) {
toast.error(err.message || 'Something went wrong.');
}
setLoading(false);
}, [params, handleItems, onSubmitUser])
const emailConfirmed = useRef(false)
useEffect(() => {
if (emailConfirmed.current) return;
emailConfirmed.current = true;
// This will only be called once when the component is mounted:
confirmEmail();
}, [confirmEmail]);
};