Reputation: 11
I'm coding a custom hook but I always get this error:
Uncaught (in promise) Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
I stop passing setState but it still doesn't work.
Custom hook, useStorage.js
import React, { useState, useEffect } from "react";
import { uploadFile, getFileUrl } from "../services/uploadFile";
export function useStorage(file, fileName , folderPath){
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
if (file) {
uploadFile(file , fileName , folderPath)
.on("state_changed",
(snapshot) => {
const progress = Math.round((snapshot.bytesTransferred / snapshot.totalBytes) * 100);
setProgress(progress);
},
(error) => {
setError(error);
},
() => {
getFileUrl(uploadFile.snapshot.ref).then((downloadURL) => {
setUrl(downloadURL)
});
}
);
}
}, [file]);
return { progress, url, error };
};
uploadFile.js
import { storage } from "../../../firebase/configuration"
import {ref, uploadBytesResumable, getDownloadURL} from "firebase/storage"
export const uploadFile = (folderPath , fileName, file) =>{
const storageRef = ref(storage , `${folderPath}${fileName}`)
const uploadTask = uploadBytesResumable(storageRef, file);
return uploadTask;
}
export const getFileUrl = async(ref) =>{
return await getDownloadURL(ref)
}
I use the hook in this component(dataFormljsx)
import { Grid, TextField, Button, CssBaseline } from '@mui/material';
import Typography from '@mui/material/Typography';
import { MobileDatePicker } from '@mui/x-date-pickers/MobileDatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import esEsLocale from 'date-fns/locale/es';
import { useState } from 'react';
import { uploadFile } from '../../services/uploadFile';
import { updateDocument } from '../../services/updateDocument';
import { useStorage } from '../../hooks/useStorage';
import { useUpdateUser } from '../../hooks/useUpdateUser';
const userExample = {
name : "John",
lastName : "Test",
secondLastName : "test",
codeforcesUsername : "test",
email : "[email protected]",
nickname : "",
birthdate : new Date(),
career : "",
cellphone : "",
currentSemester: "",
github : "",
facebook : "",
instagram : "",
faculty : "",
omegaup : "",
generation : 2,
inscription : false,
photo : "", //missing
problemsSolved : null,
role : "student",
rules : false, //missing
team : "",
inscriptionComprobant : ""
}
const ProfileDataForm = () =>{
const [formValues , setFormValues] = useState(userExample);
//let navigate = useNavigate();
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormValues({
...formValues,
[name]: value,
});
};
const handleSubmit = async (event) => {
event.preventDefault();
var uid = "e9O4OfTsNRfPITvtcsF97YgMaYT2"
//upload comprobant
// uplaod photo
const {photo , inscriptionComprobant} = formValues
const {progressPhoto , urlPhoto , errorPhoto} = useStorage(photo , "ejem.jpeg" , "images/userPhotos")
const {progressPdf , urlPdf , errorPdf} = useStorage(inscriptionComprobant, "ejem.pdf" , "pdfs/inscriptionComprobant")
if(!errorPhoto && errorPdf){
const [newDoc , updateError] = useUpdateUser(uid,
{
...formValues,
photo : urlPhoto,
inscriptionComprobant : urlPdf
}
)
if(updateError) console.log(updateError);
else setFormValues(newDoc);
}
}
const handleDatePicker = (value) => {
setFormValues({
...formValues,
birthdate : value
})
}
const handleOnChangeFile = (e) => {
const { name, files } = e.target;
setFormValues({
...formValues,
[name]: files[0],
});
}
console.log(formValues)
return(
<form>
<CssBaseline/>
<Grid container spacing={2} >
<Grid item xs={4}>
<TextField
id = "name"
label = "Nombres"
variant="outlined"
fullWidth margin="normal"
onChange={handleInputChange}
type = "text"
value = {formValues.name}
name = "name"
required />
</Grid>
<Grid item xs={4}>
<TextField id = "lastName"
label = "Primer Apellido"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
type = "text"
value = {formValues.lastName}
name = "lastName"
required/>
</Grid>
<Grid item xs={4}>
<TextField id = "secondLastName"
label = "Segundo Apellido"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
type = "text"
value = {formValues.secondLastName}
name = "secondLastName" />
</Grid>
<Grid item xs={3}>
<TextField id = "nickName"
label = "Apodo"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.nickname}
name = "nickname"
required />
</Grid>
<Grid item xs={5}>
<TextField id = "email"
label = "Correo"
variant="outlined"
fullWidth
margin="normal"
type= "email"
onChange={handleInputChange}
value = {formValues.email}
name = "email"
required/>
</Grid>
<Grid item xs={4}>
<TextField id = "cellphone"
label = "Número Celular"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.cellphone}
name = "cellphone"
required />
</Grid>
<LocalizationProvider dateAdapter={AdapterDateFns} adapterLocale = {esEsLocale}>
<MobileDatePicker
label="Fecha de nacimiento"
inputFormat="dd/MM/yyyy"
value={formValues.birthdate}
onChange={handleDatePicker}
renderInput={(params) =>
<Grid item xs= {3}>
<TextField {...params} margin = "normal"/>
</Grid>
}
/>
</LocalizationProvider>
<Grid item xs={3}>
<TextField id = "faculty"
label = "Facultad"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.faculty}
name = "faculty"
required />
</Grid>
<Grid item xs={6}>
<TextField id = "career"
label = "Carrera actual"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.career}
name = "career"
required />
</Grid>
<Grid item xs={3}>
<TextField id = "currSemester"
label = "Semestre Actual"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.currentSemester}
name = "currentSemester"
type= "number"
required />
</Grid>
<Grid item xs={4}>
<TextField id = "codeforcesUsername"
label = "Usuario de codeforces"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.codeforcesUsername}
name = "codeforcesUsername"
required />
</Grid>
<Grid item xs={5}>
<TextField id = "github"
label = "Github"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.github}
name = "github"
required />
</Grid>
<Grid item xs={4}>
<TextField id = "facebook"
label = "Facebook"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.facebook}
name = "facebook"
required />
</Grid>
<Grid item xs={4}>
<TextField id = "instagram"
label = "Instagram"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.instagram}
name = "instagram"
required />
</Grid>
<Grid item xs={4}>
<TextField id = "omegaup"
label = "Omegaup"
variant="outlined"
fullWidth
margin="normal"
onChange={handleInputChange}
value = {formValues.omegaup}
name = "omegaup"
required />
</Grid>
<Grid item xs={12}>
<Button variant="contained" component="label" >
Subir foto de perfil
<input hidden accept="image/*" type="file" size = "2mb" name = "photo" onChange = {handleOnChangeFile}
/>
</Button>
</Grid>
<Grid item xs={12}>
<Button variant="contained" component="label" >
Subir comprobante de inscripcion
<input hidden accept="application/pdf" type="file" size = "5mb" onChange={handleOnChangeFile}
name = "inscriptionComprobant"
/>
</Button>
</Grid>
<Grid item xs={12}>
<Button variant="contained" onClick = {handleSubmit}>
Actualizar
</Button>
</Grid>
</Grid>
</form>
)
}
export default ProfileDataForm
Upvotes: 0
Views: 482
Reputation: 626
You cannot call the hook inside a function of the functional component, the hook call needs to be in the scope of the functional component, here I explain better
const ProfileDataForm = () =>{
const [formValues , setFormValues] = useState(userExample);
//let navigate = useNavigate();
// Call useStorage hook and all hooks here
const handleInputChange = (e) => {
const { name, value } = e.target;
setFormValues({
...formValues,
[name]: value,
});
};
const handleSubmit = async (event) => {
event.preventDefault();
var uid = "e9O4OfTsNRfPITvtcsF97YgMaYT2"
//upload comprobant
// uplaod photo
const {photo , inscriptionComprobant} = formValues
const {progressPhoto , urlPhoto , errorPhoto} = useStorage(photo , "ejem.jpeg" , "images/userPhotos")
const {progressPdf , urlPdf , errorPdf} = useStorage(inscriptionComprobant, "ejem.pdf" , "pdfs/inscriptionComprobant")
if(!errorPhoto && errorPdf){
const [newDoc , updateError] = useUpdateUser(uid,
{
...formValues,
photo : urlPhoto,
inscriptionComprobant : urlPdf
}
)
if(updateError) console.log(updateError);
else setFormValues(newDoc);
}
}
const handleDatePicker = (value) => {
setFormValues({
...formValues,
birthdate : value
})
}
Upvotes: 1