auth.currentUser.updateProfile is not a function - reactjs

I'm trying to change the username and the user's profile img of the user but it misses the function I've imported. I've tried using auth.currentUser.updateProfile but it does not recognize it as a function I cannot even put await on front of the function.
It happens when doneHandle is called. Here the auth is basically the "const auth = getAuth(app);" initialization of the application.
import React, { useContext, useState } from 'react';
import { AuthContext } from '../App';
import { updateProfile } from 'firebase/auth';
export default function Dashboard() {
const { currentUser, auth } = useContext(AuthContext);
const [content, setContent] = useState('');
const [open, setOpen] = useState(false);
const [dia, setDia] = useState('');
const handleClickOpen = (e) => {
setDia(e.target.value);
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const doneHandle = (e) => {
if (e.target.value === 'Profile') {
auth.currentUser
.updateProfile({
displayName: content,
})
.then(function (error) {
console.log(error);
});
} else {
currentUser
.updateProfile({
photoURL: content,
})
.then(function (error) {
console.log(error);
});
}
};
return (
<Removed some code that was not related to the ques>
<Dialog open={open} onClose={handleClose}>
<DialogContent>
<DialogContentText>
{dia === 'Profile'
? 'Enter your name down below.'
: 'Please paste the direct url to the image. '}
</DialogContentText>
<TextField
autoFocus
margin='dense'
id='name'
type='email'
fullWidth
variant='standard'
value={content}
onChange={(e) => {
setContent(e.target.value);
}}
/>
</DialogContent>
<Button
value={dia}
onClick={(e) => {
doneHandle(e);
}}
>
Done
</Button>
</Dialog>
</div>
</div>
);
}

You're importing updateProfile as a top-level function from the v9 modular SDK, but then try to invoke a updateProfile method on the user object - which is the namspaced syntax for the v8 SDK. You can't just mix and match those syntaxes.
As shown in the code sample in the documentation on updating a user profile, you should call the top-level function and pass the current user as arguments:
updateProfile(currentUser, {
displayName: content
})

Related

Function setDoc() called with invalid data. Unsupported field value: a custom UserImpl object (found in field owner in document CreatedClasses)

This is the first time I'm asking a question here and also a newbie to coding. I'm trying to clone google classroom.
I am trying to use firestore to make a db collection when creating the class. But when I click create it doesn't create the class and create the db in firestore. It shows that the setDoc() function is invalid. Im using firestore version 9 (modular)
Here is my Form.js file. (The firestore related code is also included here)
import { DialogActions, TextField , Button} from "#material-ui/core"
import React, {useState} from 'react'
import { useLocalContext, useAuth } from '../../../context/AuthContext'
import { v4 as uuidV4 } from 'uuid'
import { db} from '../../../firebase'
import { collection, doc, setDoc } from "firebase/firestore"
const Form = () => {
const [className, setClassName] = useState('')
const [Level, setLevel] = useState('')
const [Batch, setBatch] = useState('')
const [Institute, setInstitute] = useState('')
const {setCreateClassDialog} = useLocalContext();
const {currentUser} = useAuth();
const addClass = async (e) => {
e.preventDefault()
const id = uuidV4()
// Add a new document with a generated id
const createClasses = doc(collection(db, 'CreatedClasses'));
await setDoc(createClasses, {
owner:currentUser,
className: className,
level: Level,
batch: Batch,
institute: Institute,
id: id
}).then (() => {
setCreateClassDialog(false);
})
}
return (
<div className='form'>
<p className="class__title">Create Class</p>
<div className='form__inputs'>
<TextField
id="filled-basic"
label="Class Name (Required)"
className="form__input"
variant="filled"
value={className}
onChange={(e) => setClassName(e.target.value)}
/>
<TextField
id="filled-basic"
label="Level/Semester (Required)"
className="form__input"
variant="filled"
value={Level}
onChange={(e) => setLevel(e.target.value)}
/>
<TextField
id="filled-basic"
label="Batch (Required)"
className="form__input"
variant="filled"
value={Batch}
onChange={(e) => setBatch(e.target.value)}
/>
<TextField
id="filled-basic"
label="Institute Name"
className="form__input"
variant="filled"
value={Institute}
onChange={(e) => setInstitute(e.target.value)}
/>
</div>
<DialogActions>
<Button onClick={addClass} color='primary'>
Create
</Button>
</DialogActions>
</div>
)
}
export default Form
And also (I don't know whether this is helpful but my context file is below)
import React, { createContext, useContext, useEffect, useState } from "react";
import {
createUserWithEmailAndPassword,
signInWithEmailAndPassword,
onAuthStateChanged,
signOut,
GoogleAuthProvider,
signInWithPopup
} from "firebase/auth";
import { auth } from "../firebase";
const AuthContext = createContext();
const AddContext = createContext()
export function useAuth() {
return useContext(AuthContext);
}
export function useLocalContext(){
return useContext(AddContext)
}
export function ContextProvider({children}){
const [createClassDialog,setCreateClassDialog] = useState(false);
const [joinClassDialog, setJoinClassDialog] = useState(false);
const value = { createClassDialog, setCreateClassDialog, joinClassDialog, setJoinClassDialog };
return <AddContext.Provider value={value}> {children} </AddContext.Provider>;
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [loading, setLoading] = useState(true)
function signup(email, password) {
return createUserWithEmailAndPassword(auth,email, password);
}
function login(email, password) {
return signInWithEmailAndPassword(auth, email, password);
}
function logout() {
return signOut(auth);
}
function resetPassword(email) {
return auth.sendPasswordResetEmail(email)
}
function googleSignIn() {
const googleAuthProvider = new GoogleAuthProvider();
return signInWithPopup(auth, googleAuthProvider);
}
function updateEmail(email) {
return currentUser.updateEmail(email)
}
function updatePassword(password) {
return currentUser.updatePassword(password)
}
useEffect(() => {
const unsubscribe = onAuthStateChanged( auth, (user) => {
setCurrentUser(user);
setLoading(false)
});
return () => {
unsubscribe();
};
}, []);
return (
<AuthContext.Provider
value={{ currentUser, login, signup, logout, googleSignIn, resetPassword,updateEmail, updatePassword }}
>
{!loading && children}
</AuthContext.Provider>
);
}
The console error message:
Try something like this, excluding the collection function from setting the document.
// Add a new document with a generated id
await setDoc(doc(db, 'CreatedClasses'), {
owner:currentUser,
className: className,
level: Level,
batch: Batch,
institute: Institute,
id: classId
}).then (() => {
setCreateClassDialog(false);
})

useEffect cleanup function? Memory leak error

I want to understand why don't work properly the useEffect hook without the AbortionController.abort function.
I have a nested route in the app.js like:
<Route path='/profile' element={<PrivateRoute />}>
<Route path='/profile' element={<Profile />} />
</Route>
than the two component:
PrivateRoute:
import { Navigate, Outlet } from 'react-router-dom';
import { useAuthStatus } from '../hooks/useAuthStatus';
export default function PrivateRoute() {
const { loggedIn, checkingStatus } = useAuthStatus();
if (checkingStatus) return <h1>Loading...</h1>;
return loggedIn ? <Outlet /> : <Navigate to='/sign-in' />;
}
Profile:
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { getAuth, updateProfile } from 'firebase/auth';
import { updateDoc, doc } from 'firebase/firestore';
import { db } from '../firebase.config';
import { toast } from 'react-toastify';
export default function Profile() {
const auth = getAuth();
const [changeDetails, setChangeDetails] = useState(false);
const [formData, setFormData] = useState({
name: auth.currentUser.displayName,
email: auth.currentUser.email,
});
const { name, email } = formData;
const navigate = useNavigate();
const onLogout = () => {
auth.signOut();
navigate('/');
};
const onSubmit = async (e) => {
try {
if (auth.currentUser.displayName !== name) {
//update display name if fb
await updateProfile(auth.currentUser, {
displayName: name,
});
//update in firestore
const userRef = doc(db, 'users', auth.currentUser.uid);
await updateDoc(userRef, {
name,
});
}
} catch (error) {
toast.error('Could not update profile details');
}
};
const onChange = (e) => {
setFormData((prev) => ({
...prev,
[e.target.id]: e.target.value,
}));
};
return (
<div className='profile'>
<header className='profileHeader'>
<p className='pageHeader'>My Profile</p>
<button type='button' className='logOut' onClick={onLogout}>
Logout
</button>
</header>
<main>
<div className='profileDetailsHeader'>
<p className='profileDetailsText'>Personal Details</p>
<p
className='changePersonalDetails'
onClick={() => {
setChangeDetails((prev) => !prev);
changeDetails && onSubmit();
}}
>
{changeDetails ? 'done' : 'change'}
</p>
</div>
<div className='profileCard'>
<form>
<input
type='text'
id='name'
className={!changeDetails ? 'profileName' : 'profileNameActive'}
disabled={!changeDetails}
value={name}
onChange={onChange}
/>
<input
type='text'
id='email'
className={!changeDetails ? 'profileEmail' : 'profileEmailActive'}
disabled={!changeDetails}
value={email}
onChange={onChange}
/>
</form>
</div>
</main>
</div>
);
}
and the custom Hook:
import { useEffect, useState } from 'react';
import { getAuth, onAuthStateChanged } from 'firebase/auth';
export function useAuthStatus() {
const [loggedIn, setLoggedIn] = useState(false);
const [checkingStatus, setCheckingStatus] = useState(true);
useEffect(() => {
const abortCont = new AbortController();
const auth = getAuth();
onAuthStateChanged(auth, (user) => {
if (user) {
setLoggedIn(true);
} else {
setLoggedIn(false);
}
setCheckingStatus(false);
});
// return () => abortCont.abort();
}, [setLoggedIn, setCheckingStatus]);
return { loggedIn, checkingStatus };
}
Can you explain me why do I get the error: Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
I found the solution with the AbortController, but still don't understand what is the problem.
The error appears randomly, sometimes when I log in, sometimes when I'm not logged in, and try to go on the profile page. The app works fine, just want to understand what happens under the hood.
If I understand, if I'm not logged in, then it will rendered the 'Sign-in' page, if I'm logged in, then the 'Profile' page will be rendered, also there is a loading page but it's not the case. So, it's simple, if I'm logged in render this page, if not, render the other page. So where is the Problem? Why do I need the AbortController function?
onAuthStateChanges will listen forever in your useEffect hook. You need to unsubscribe every time the hook is run otherwise you will have these memory leaks. In your case the change of the users auth state will try to called setLoggedIn even when the component has been unmounted.
Looking at the documentation for onAuthStateChanged (https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#onauthstatechanged) it returns a firebase.Unsubscribe.
You'll have to do something like this:
useEffect(() => {
const auth = getAuth();
const unsubscribe = onAuthStateChanged(auth, (user) => {
if (user) {
setLoggedIn(true);
} else {
setLoggedIn(false);
}
setCheckingStatus(false);
});
return () => unsubscribe();
})
The callback you can optionally return in a useEffect hook is used for cleanup on subsequent calls.

Create a user document after creating a user in authentication in firebase

I'm trying to figure out how to create a user document in firestore after a user auth record is created.
My current attempt is below.
When i add the async/await the code generates error messages. When I remove them, the authentication part works to create a user record in the authentication part of firebase, but the firestore record is not created. No error message is generated.
Can anyone see what's going wrong?
import React, {useState} from 'react';
import { auth, firestore } from '../../../services/firebase/firebase';
import { useHistory } from 'react-router-dom';
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField';
import Dialog from '#material-ui/core/Dialog';
import DialogActions from '#material-ui/core/DialogActions';
import DialogContent from '#material-ui/core/DialogContent';
import DialogContentText from '#material-ui/core/DialogContentText';
import DialogTitle from '#material-ui/core/DialogTitle';
import { Buttons } from '../navigation/styles';
export default function FormDialog() {
const [open, setOpen] = React.useState(false);
let [loading, setLoading] = useState(false);
const history = useHistory();
const [displayName, setDisplayName ] = useState('');
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const [error, setError] = useState(null);
const handleClickOpen = () => {
setOpen(true);
};
const handleClose = () => {
setOpen(false);
};
const handleSubmit = async (event) => {
setLoading(true);
event.preventDefault();
auth.createUserWithEmailAndPassword( email, password)
THE ATTEMPT BELOW LOGS THE UID, BUT SAYS TypeError: user.updateProfile
is not a function
.then((res) => {
console.log("logging user", (auth.currentUser.uid) );
const user = auth.currentUser.uid;
return user.updateProfile({
displayName: displayName
})
firestore.collection('users').doc(auth.currentUser.uid)
.set({
fullName: displayName,
createdAt: firestore.fieldValue.serverTimestamp(),
})
})
THIS IS ANOTHER ATTEMPT, WHICH ASLO DOESNT WORK TO MAKE THE USER
DOCUMENT IN FIRESTORE
.then(() => {
if (auth.currentUser != null) {
auth.currentUser.updateProfile({
displayName: displayName
})
firestore.collection('users').doc(auth.currentUser.uid)
.set({
fullName: displayName,
createdAt: firestore.fieldValue.serverTimestamp(),
})
}
})
//THIS IS ANOTHER ATTEMPT, IN THE ALTERNATIVE TO THE ABOVE, WHICH ALSO
DOESNT WORK
.then((res) => {
const user = auth.currentUser;
return user.updateProfile({
displayName: displayName
})
firestore.collection('users').doc(auth.currentUser.uid)
.set({
fullName: displayName,
createdAt: firestore.fieldValue.serverTimestamp(),
})
})
.then(() => {
history.push("/");
})
.catch(error => {
console.error(error);
})
.then(() => {
clear();
})
.then(() => {
handleClose()
})
.finally(() => {
setLoading(false);
});
};
THIS IS A FURTHER ATTEMPT, WHICH I CAN'T TEST BECAUSE SOMETHING ABOUT THE THEN STATEMENT THAT TRIES TO PUSH HISTORY IS CONSIDERED TO HAVE A PARSING ERROR. I CAN'T FIND ANY TUTORIALS ABOUT HOW TO FIGURE OUT SOLVING THOSE.
const createUserDocument = async (user, displayName) => {
if (!user) return;
const userRef = firestore.doc(`users/${user.uid}`);
const snapshot = await userRef.get();
if (!snapshot.exists) {
const { email } = user;
const { displayName } = displayName;
try {
await userRef.set({
displayName,
email,
createdAt: new Date(),
});
} catch (error) {
console.log('Error in creating user', error);
}
}
};
const handleSubmit = async (event) => {
setLoading(true);
event.preventDefault();
try {
const { user } = await auth.createUserWithEmailAndPassword(
email,
password
);
await createUserDocument(user, { displayName });
} catch (error) {
console.log('error', error);
}
.then(() => {
history.push("/");
})
.then(() => {
clear();
})
.then(() => {
handleClose()
})
.finally(() => {
setLoading(false);
});
};
//continuing after all current attempts
const onChangeHandler = event => {
const { name, value } = event.currentTarget;
if (name === "userEmail") {
setEmail(value);
} else if (name === "userPassword") {
setPassword(value);
} else if (name === "displayName") {
setDisplayName(value);
}
};
const clear = () => {
setDisplayName("");
setEmail("");
setPassword("");
};
return (
<div>
<Buttons onClick={handleClickOpen}>
Join
</Buttons>
<Dialog open={open} onClose={handleClose} aria-labelledby="form-dialog-title">
<DialogTitle id="form-dialog-title">Join the waitlist</DialogTitle>
<DialogContent>
<DialogContentText>
Join
</DialogContentText>
<TextField
autoFocus
margin="dense"
label="Full name"
type="text"
fullWidth
name="displayName"
value={displayName}
placeholder="Jill Green"
id="displayName"
onChange={event => onChangeHandler(event)}
/>
<TextField
margin="dense"
label="Email Address"
type="email"
fullWidth
name="userEmail"
value={email}
placeholder="email address"
id="userEmail"
onChange={event => onChangeHandler(event)}
/>
<TextField
margin="dense"
label="Password"
type="password"
fullWidth
name="userPassword"
value={password}
id="userPassword"
placeholder="Minimum 6 characters"
onChange={event => onChangeHandler(event)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose} color="primary">
Cancel
</Button>
<Button
onClick={handleSubmit}
color="primary">
Register
</Button>
</DialogActions>
</Dialog>
</div>
);
}
Apart from ongoing issues trying to figure out how to record timestamps in firebase, this works to create the user document record.
const handleSubmit = async (event) => {
setLoading(true);
event.preventDefault();
auth.createUserWithEmailAndPassword(
email,
password
)
.then(credential => {
if (credential && credential.user) {
firestore.collection("users")
.doc(credential.user.uid)
.set({
email: email,
displayName: displayName,
// createdAt: firestore.Timestamp.now()
// createdAt: firestore.fieldValue.serverTimestamp()
// createdAt: firebase.firestore.fieldValue.serverTimestamp()
});
history.push("/");
}
})

How i can create private and public routes in NextJs?

I'm studying Nextjs, I come from React and a lot seems to be the same but I was lost with the authentication and private routes.
I looked for a lot of codes on the internet, but either they broke, they didn't make sense to me, or they didn't explain my doubts correctly. My scenario is basically:
I have an application
This application has public and private routes
Users need to login to access private routes
Private routes have the same Navbar
My questions are:
How to create private routes using ReactContext.
How to share the same NavBar between pages (Without having to place the NavBar component on each screen)
How to correctly authenticate a user with my own code using preferably ReactContext
How to reset the routes after authentication (The user is unable to return to the login screen if he clicks the back button on the browser)
How to correctly save the JWT token so that it saves the user's session for longer so that he does not need to log in again
My code is working so far, but I'm sure it is horrible and completely flawed.
I have the following files:
_app.js (Root of the Nextjs project)
index.js (Login page)
privateRoute.js (File that verifies if the user is logged in and allows or not his access)
userContext.js (File that saves user information to be accessed by other components and pages)
NavContext.js (File that checks whether someone is logged in to render the NavBar or not)
_app.js
function MyApp({ Component, pageProps }) {
return (
<UserContextFunc>
<NavContext>
<Component {...pageProps} />
</NavContext>
</UserContextFunc>
);
}
export default MyApp;
index.js
export default function App() {
const [loading, setLoading] = React.useState(false);
const [email, setEmail] = React.useState("");
const [password, setPassword] = React.useState("");
const { setState } = React.useContext(UserContext);
const router = useRouter();
const login = () => {
setLoading(true);
fetch("/api/auth/login", {
method: "POST",
body: JSON.stringify({
email,
password,
}),
headers: {
"Content-Type": "application/json",
},
})
.then((res) => {
setLoading(false);
if (res.status === 200) {
res.json().then(({ token, roles }) => {
setState({ roles, token });
window.localStorage.setItem(
"rou",
btoa(unescape(encodeURIComponent(JSON.stringify(roles))))
);
window.localStorage.setItem("token", token);
router.replace("/app/adm/home");
});
}
})
.catch((err) => {
});
};
return (
<>
<ReactNotification />
<label htmlFor="exampleInputEmail1" className="form-label">
Email
</label>
<input
type="text"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="form-control"
/>
<label htmlFor="exampleInputPassword1" className="form-label">
Senha
</label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="form-control"
/>
<button
onClick={() => login()}
type="button"
className="btn btn-primary btn-block"
>
{loading ? (
<div
className="spinner-border text-light spinner-border-sm"
role="status"
>
<span className="visually-hidden"></span>
</div>
) : (
"Login"
)}
</button>
</>
);
}
privateRoute.js
const indexPage = "/";
const withAuth = (Component) => {
const Auth = (props) => {
const { setState } = React.useContext(UserContext);
const router = useRouter();
React.useEffect(() => {
const token = window.localStorage.getItem("token");
var roles = window.localStorage.getItem("rou");
if (roles) {
roles = decodeURIComponent(escape(atob(roles)));
}
if (!token || !roles || token == "undefined") {
window.localStorage.removeItem("token");
window.localStorage.removeItem("rou");
return router.replace(indexPage);
} else {
setState({ roles, token });
}
}, []);
return <Component {...props} />;
};
if (Component.getInitialProps) {
Auth.getInitialProps = Component.getInitialProps;
}
return Auth;
};
export default withAuth;
userContext.js
export const UserContext = React.createContext();
export const UserContextFunc = ({ children }) => {
const [state, dispatch] = React.useReducer(
(prevState, action) => {
switch (action.type) {
case 'SET':
return {
...prevState,
...action.newState,
};
}
},
{
roles: []
}
);
const setState = newState => {
dispatch({ type: 'SET', newState });
}
const getState = async () => {
return state
}
return (
<UserContext.Provider value={{ getState, setState, state }}>
{children}
</UserContext.Provider>
);
}
NavContext.js
function NavContext(props) {
const { state } = React.useContext(UserContext);
return (
<>
{state.roles && state.token && <NavBar />}
{props.children}
</>
);
}
export default NavContext;
In private files I export them this way
import withPrivateRoute from "../../../utils/privateRoute";
...
export default withPrivateRoute(Dashboard);
I hope I managed to explain it well, I know it's a lot, but I didn't find any content explaining how to create a private route in Nextjs or how to authenticate correctly without using the authentication templates found in the Next documentation.
This code works, but as I said it seems completely wrong. I accept tips too.

Making an asynchronous call to an api doen't work through redux actions

I'm building this news website which takes input the news topic (that the user wants to see), fetches data from an api and renders them. But when I dispatch the action, the user inputted topic doesn't reach searchBlog.js. See below for clarity.
All the import/export works fine, I've tested them.
The SearchBar component from where the action is called
function SearchBar() {
const classes = useStyles();
const [search, setSearch] = useState('farmer');
const handleChange = e => {
setSearch(e.target.value);
};
const handleSubmit = e => {
e.preventDefault();
searchBlogs(search);
};
return (
<Paper
component="form"
className={classes.root}
onSubmit={handleSubmit}
>
<InputBase
className={classes.input}
placeholder="Type your search"
inputProps={{ 'aria-label': 'type your search' }}
onChange={handleChange}
/>
<IconButton
type="submit"
className={classes.iconButton}
aria-label="search"
>
<SearchOutlined />
</IconButton>
</Paper>
);
}
searchBlogs.js - action that needs to work but doesn't
export const searchBlogs = query => async dispatch => {
console.log(query); // This line never prints
dispatch({ type: SEARCH_BLOGS, payload: query });
try {
const data = await fetchNews(query);
dispatch({ type: UPDATE_BLOGS, payload: data });
} catch (err) {
dispatch({ type: SEARCH_FAIL, payload: err.message });
}
};
But if I remove the thunk feature (async dispatch callback)
export const searchBlogs = query => {
console.log(query); // It prints now
...
}
fetchNews.js - If this helps
export const fetchNews = query =>
axios.get(URL + `q=${query}&apiKey=${process.env.REACT_APP_NEWS_API}`);
I don't understand the error here. Is it something related to not handling the async call correctly? Any help would be appreciated.
You're not dispatching the action.
import { useDispatch } from 'react-redux'
function SearchBar() {
const dispatch = useDispatch()
const [search, setSearch] = useState('farmer')
const handleSubmit = (e) => {
e.preventDefault()
dispatch(searchBlogs(search))
}
// rest of the code
}
Use connect() function connects a React component to a Redux store.
export default connect(null, { searchBlogs } )(SearchBar);
Then you need to get action from component props something like this:
function SearchBar({searchBlogs}) {
const classes = useStyles();
const [search, setSearch] = useState('farmer');
const handleChange = e => {
setSearch(e.target.value);
};
const handleSubmit = e => {
e.preventDefault();
searchBlogs(search);
};
return (
<Paper
component="form"
className={classes.root}
onSubmit={handleSubmit}
>
<InputBase
className={classes.input}
placeholder="Type your search"
inputProps={{ 'aria-label': 'type your search' }}
onChange={handleChange}
/>
<IconButton
type="submit"
className={classes.iconButton}
aria-label="search"
>
<SearchOutlined />
</IconButton>
</Paper>
);
}
You're getting this issue due to the fact you are calling an Asynchronous Function inside a Synchronous Function.
An immediate fix is to ammend your handleSubmit method:
const handleSubmit = async e => {
e.preventDefault();
// console.log(search) => This line works so search is non-empty
await searchBlogs(search);
};
However I'd also highly recommend you read the following related question:
Call An Asynchronous Javascript Function Synchronously

Resources