Handling custom email handlers with Firebase + NextJS - javascript

I've created the following code to have access to custom email handlers, as the firebase docs recommends.
import { useEffect } from 'react';
import { useRouter } from 'next/router'
import RecoverEmail from '../components/FirebaseHandler/RecoverEmail';
import ResetPassword from '../components/FirebaseHandler/ResetPassword';
import VerifyEmail from '../components/FirebaseHandler/VerifyEmail';
import useState from 'react-usestateref'
// http://localhost:3000/action?mode=resetPassword&oobCode=ABC123&apiKey=AIzaSy
// mode - The user management action to be completed
// oobCode - A one-time code, used to identify and verify a request
// apiKey - Your Firebase project's API key, provided for convenience
const Action = (props) => {
const router = useRouter();
const [mode, setMode, modeRef] = useState('')
const [actionCode, setActionCode, actionCodeRef] = useState('')
useEffect(() => {
console.log(router.query)
console.log('before:' + mode)
setMode(router.query.mode)
setActionCode(router.query.oobCode)
console.log('after:' + modeRef.current)
}, [router.isReady]);
switch (modeRef.current) {
case 'resetPassword':
// Display reset password handler and UI.
return <ResetPassword actionCode={actionCodeRef.current} />;
break
case 'recoverEmail':
// Display email recovery handler and UI.
return <RecoverEmail actionCode={actionCodeRef.current} />;
break
case 'verifyEmail':
// Display email verification handler and UI.
return <VerifyEmail actionCode={actionCodeRef.current} />;
break
default:
// Error: invalid mode.
return (
<div className="Action">
<h1>Error encountered</h1>
<p>The selected page mode is invalid.</p>
</div>
);
}
}
export default Action;
I've managed to success with the 'recover email' and 'verify email' cases, but I've failed achieving something with 'reset password'. I don't know what's wrong, but when I get the link and I open it, the case 'reset password' doesn't execute (it directly goes to the default one), or if it does, then I get the following 404 error from firebase, instead of being shown the ResetPassword component that allows the user to execute the functions.
As I mentioned before, I don't know exactly what could be wrong with this case since the other two are perfectly working, so any clue would be very appreciated. Thank you.

Related

How to open app to specific page after click notification from bar by using react-native-firebase/messaging(FCM)?

Is there any way can open app to specific page after click notification by using react-native-firebase/messaging(FCM)?
I didn't find information from document.
#react-native-firebase version:
"#react-native-firebase/app": "^15.3.0",
"#react-native-firebase/messaging": "^15.3.0",
code just only:
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* #format
* #flow strict-local
*/
import React, {useEffect} from 'react';
import {Alert, StyleSheet, Text, View} from 'react-native';
import messaging from '#react-native-firebase/messaging';
import styles from '../css/styles';
let fcmUnsubscribe = null;
function Notify(props) {
useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
});
return unsubscribe;
}, []);
return (
<View style={styles.sectionContainer}>
<Text style={styles.highlight}>{props.test}</Text>
</View>
);
}
export default Notify;
I use one non standard approach, regarding how to boost fcm functions in my apps. You have remoteMessage over which you send payload for notification... Well in this payload I put everything I need for app, and separate this with | for example. So my remoteMessage string is like this:
Some text notification for display to user|page-to-open|part-of-page-where-to-position|other-custom-data-needed
Then before displaying this in notification alert box, I first parse it to array or few variables, and then only part of this string related to notification text send to display, and other variables use for opening specific pages or some other things.
Something like this (this is JS as it was first at hand to copy you, but similar applies for RN)
messaging.onBackgroundMessage(function(payload) {
var notificationTitle = payload.data.title;
var notificationBody = payload.data.body.substring(0, payload.data.body.indexOf("|"));
var notificationURL = payload.data.body.split("|")[1];
var notificationStatusURL = payload.data.body.split("|")[2];
You can do like below
useEffect(() => {
const unsubscribe = messaging().onMessage(async remoteMessage => {
Alert.alert('A new FCM message arrived!', JSON.stringify(remoteMessage));
if (remoteMessage?.data?.screen_name) {
navigation.navigate(remoteMessage?.data?.screen_name)
};
});
return unsubscribe;
}, []);
Note please check that your function includes in navigation container
Otherwise you can use useNavigation hooks
and check screen_name param with your param name which you are sending from firebase

useEffect running two times, but my dependencies array is empty, why is this happening? [duplicate]

I am new to reactJS and am writing code so that before the data is loaded from DB, it will show loading message, and then after it is loaded, render components with the loaded data. To do this, I am using both useState hook and useEffect hook. Here is the code:
The problem is, useEffect is triggered twice when I check with console.log. The code is thus querying the same data twice, which should be avoided.
Below is the code that I wrote:
import React from 'react';
import './App.css';
import {useState,useEffect} from 'react';
import Postspreview from '../components/Postspreview'
const indexarray=[]; //The array to which the fetched data will be pushed
function Home() {
const [isLoading,setLoad]=useState(true);
useEffect(()=>{
/*
Query logic to query from DB and push to indexarray
*/
setLoad(false); // To indicate that the loading is complete
})
},[]);
if (isLoading===true){
console.log("Loading");
return <div>This is loading...</div>
}
else {
console.log("Loaded!"); //This is actually logged twice.
return (
<div>
<div className="posts_preview_columns">
{indexarray.map(indexarray=>
<Postspreview
username={indexarray.username}
idThumbnail={indexarray.profile_thumbnail}
nickname={indexarray.nickname}
postThumbnail={indexarray.photolink}
/>
)}
</div>
</div>
);
}
}
export default Home;
Can someone help me out in understanding why it is called twice, and how to fix the code properly?
Thank you very much!
Put the console.log inside the useEffect
Probably you have other side effects that cause the component to rerender but the useEffect itself will only be called once. You can see this for sure with the following code.
useEffect(()=>{
/*
Query logic
*/
console.log('i fire once');
},[]);
If the log "i fire once" is triggered more than once it means your issue is
one of 3 things.
This component appears more than once in your page
This one should be obvious, your component is in the page a couple of times and each one will mount and run the useEffect
Something higher up the tree is unmounting and remounting
The component is being forced to unmount and remount on its initial render. This could be something like a "key" change happening higher up the tree. you need to go up each level with this useEffect until it renders only once. then you should be able to find the cause or the remount.
React.Strict mode is on
StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them (which can be quite useful).
This answer was pointed out by #johnhendirx and written by #rangfu, see link and give him some love if this was your problem. If you're having issues because of this it usually means you're not using useEffect for its intended purpose. There's some great information about this in the beta docs you can read that here
Remove <React.StrictMode> from index.js
This code will be
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
this
root.render(
<App />
);
React StrictMode renders components twice on dev server
You are most likely checking the issue on a dev environment with strict mode enabled.
To validate this is the case, search for <React.StrictMode> tag and remove it, or build for production. The double render issue should be gone.
From React official documentation
Strict mode can’t automatically detect side effects for you, but it can help you spot them by making them a little more deterministic. This is done by intentionally double-invoking the following functions:
Functions passed to useState, useMemo, or useReducer
[...]
Strict Mode - Reactjs docs
Similar question here My React Component is rendering twice because of Strict Mode
Please check your index.js
<React.StrictMode>
<App />
</React.StrictMode>
Remove the <React.StrictMode> wrapper
you should now fire once
root.render(
<App />
);
react root > index.js > remove <React.StrictMode> wrapper
It is the feature of ReactJS while we use React.StrictMode. StrictMode activates additional checks and warnings for its descendants nodes. Because app should not crash in case of any bad practice in code. We can say StrictMode is a safety check to verify the component twice to detect an error.
You will get this <React.StricyMode> at root of the component.
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
if you want to restrict components to render twice, You can remove <React.StrictMode> and check it. But It is necessary to use StrictMode to detect a run time error in case of bad code practice.
if you are using Next js, change reactStrictMode from "true" to false :
add this to your next.config.js
reactStrictMode: false,
I have found a very good explanation behind twice component mounting in React 18. UseEffect called twice in React
Note: In production, it works fine. Under strict mode in the development environment, twice mounting is intentionally added to handle the errors and required cleanups.
I'm using this as my alternative useFocusEffect. I used nested react navigation stacks like tabs and drawers and refactoring using useEffect doesn't work on me as expected.
import React, { useEffect, useState } from 'react'
import { useFocusEffect } from '#react-navigation/native'
const app = () = {
const [isloaded, setLoaded] = useState(false)
useFocusEffect(() => {
if (!isloaded) {
console.log('This should called once')
setLoaded(true)
}
return () => {}
}, [])
}
Also, there's an instance that you navigating twice on the screen.
Not sure why you won't put the result in state, here is an example that calls the effect once so you must have done something in code not posted that makes it render again:
const App = () => {
const [isLoading, setLoad] = React.useState(true)
const [data, setData] = React.useState([])
React.useEffect(() => {
console.log('in effect')
fetch('https://jsonplaceholder.typicode.com/todos')
.then(result => result.json())
.then(data => {
setLoad(false)//causes re render
setData(data)//causes re render
})
},[])
//first log in console, effect happens after render
console.log('rendering:', data.length, isLoading)
return <pre>{JSON.stringify(data, undefined, 2)}</pre>
}
//render app
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
To prevent the extra render you can combine data and loading in one state:
const useIsMounted = () => {
const isMounted = React.useRef(false);
React.useEffect(() => {
isMounted.current = true;
return () => isMounted.current = false;
}, []);
return isMounted;
};
const App = () => {
const [result, setResult] = React.useState({
loading: true,
data: []
})
const isMounted = useIsMounted();
React.useEffect(() => {
console.log('in effect')
fetch('https://jsonplaceholder.typicode.com/todos')
.then(result => result.json())
.then(data => {
//before setting state in async function you should
// alsways check if the component is still mounted or
// react will spit out warnings
isMounted.current && setResult({ loading: false, data })
})
},[isMounted])
console.log(
'rendering:',
result.data.length,
result.loading
)
return (
<pre>{JSON.stringify(result.data, undefined, 2)}</pre>
)
}
//render app
ReactDOM.render(<App />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
The new React docs (currently in beta) have a section describing precisely this behavior:
How to handle the Effect firing twice in development
From the docs:
Usually, the answer is to implement the cleanup function. The cleanup function should stop or undo whatever the Effect was doing. The rule of thumb is that the user shouldn’t be able to distinguish between the Effect running once (as in production) and a setup → cleanup → setup sequence (as you’d see in development).
So this warning should make you double check your useEffect, usually means you need to implement a cleanup function.
This may not be the ideal solution. But I used a workaround.
var ranonce = false;
useEffect(() => {
if (!ranonce) {
//Run you code
ranonce = true
}
}, [])
Even though useEffect runs twice code that matters only run once.
As others have already pointed out, this happens most likely due to a Strict Mode feature introduced in React 18.0.
I wrote a blog post that explains why this is happening and what you can do to work around it.
But if you just want to see the code, here you go:
let initialized = false
useEffect(() => {
if (!initialized) {
initialized = true
// My actual effect logic...
...
}
}, [])
Or as a re-usable hook:
import type { DependencyList, EffectCallback } from "react"
import { useEffect } from "react"
export function useEffectUnsafe(effect: EffectCallback, deps: DependencyList) {
let initialized = false
useEffect(() => {
if (!initialized) {
initialized = true
effect()
}
}, deps)
}
Please keep in mind that you should only resort to this solution if you absolutely have to!
I've had this issue where something like:
const [onChainNFTs, setOnChainNFTs] = useState([]);
would trigger this useEffect twice:
useEffect(() => {
console.log('do something as initial state of onChainNFTs changed'); // triggered 2 times
}, [onChainNFTs]);
I confirmed that the component MOUNTED ONLY ONCE and setOnChainNFTs was NOT called more than once - so this was not the issue.
I fixed it by converting the initial state of onChainNFTs to null and doing a null check.
e.g.
const [onChainNFTs, setOnChainNFTs] = useState(null);
useEffect(() => {
if (onChainNFTs !== null) {
console.log('do something as initial state of onChainNFTs changed'); // triggered 1 time!
}
}, [onChainNFTs]);
Here is the custom hook for your purpose. It might help in your case.
import {
useRef,
EffectCallback,
DependencyList,
useEffect
} from 'react';
/**
*
* #param effect
* #param dependencies
* #description Hook to prevent running the useEffect on the first render
*
*/
export default function useNoInitialEffect(
effect: EffectCallback,
dependancies?: DependencyList
) {
//Preserving the true by default as initial render cycle
const initialRender = useRef(true);
useEffect(() => {
let effectReturns: void | (() => void) = () => {};
/**
* Updating the ref to false on the first render, causing
* subsequent render to execute the effect
*
*/
if (initialRender.current) {
initialRender.current = false;
} else {
effectReturns = effect();
}
/**
* Preserving and allowing the Destructor returned by the effect
* to execute on component unmount and perform cleanup if
* required.
*
*/
if (effectReturns && typeof effectReturns === 'function') {
return effectReturns;
}
return undefined;
}, dependancies);
}
There is nothing to worry about. When you are running React in development mode. It will sometimes run twice. Test it in prod environment and your useEffect will only run once. Stop Worrying!!
It is strict mode in my case. Remove strict mode component at index.tsx or index.jsx
If someone comes here using NextJS 13, in order to remove the Strict mode you need to add the following on the next.config.js file:
const nextConfig = {
reactStrictMode: false
}
module.exports = nextConfig
When I created the project it used "Strict mode" by default that's why I must set it explicitly.
Ok this is maybe a bit late to comment on this - but I found a rather useful solution which is 100% react.
In my case I have a token which I'm using to make a POST request which logs out my current user.
I'm using a reducer with state like this:
export const INITIAL_STATE = {
token: null
}
export const logoutReducer = (state, action) => {
switch (action.type) {
case ACTION_SET_TOKEN :
state = {
...state,
[action.name] : action.value
};
return state;
default:
throw new Error(`Invalid action: ${action}`);
}
}
export const ACTION_SET_TOKEN = 0x1;
Then in my component I'm checking the state like this:
import {useEffect, useReducer} from 'react';
import {INITIAL_STATE, ACTION_SET_TOKEN, logoutReducer} from "../reducers/logoutReducer";
const Logout = () => {
const router = useRouter();
const [state, dispatch] = useReducer(logoutReducer, INITIAL_STATE);
useEffect(() => {
if (!state.token) {
let token = 'x' // .... get your token here, i'm using some event to get my token
dispatch(
{
type : ACTION_SET_TOKEN,
name : 'token',
value : token
}
);
} else {
// make your POST request here
}
}
The design is actually nice - you have the opportunity to discard your token from storage after the POST request, make sure the POST succeeds before anything. For async stuff you can use the form :
POST().then(async() => {}).catch(async() => {}).finally(async() => {})
all running inside useEffect - works 100% and within I think what the REACT developers had in mind - this pointed out that I actually had more cleanup to do (like removing my tokens from storage etc) before everything was working but now I can navigate to and from my logout page without anything weird happening.
My two cents...
I used CodeSandbox and removing prevented the issue.
CodeSandbox_sample

Router.push is returning my objects as undefined, the array length is correct but the value is "" in Next.js [duplicate]

I got a problem with my dynamic route. It look like this
[lang]/abc
I am trying to get query value from [lang] but when I using useRouter/withRouter i got query during 2-3 render of page ( on first i got query.lang = undefined ). its possible to get in 1 render or use any technique ?
I found something:
isReady: boolean - Whether the router fields are updated client-side and ready for use. Should only be used inside of useEffect methods and not for conditionally rendering on the server.
https://nextjs.org/docs/api-reference/next/router#router-object
And the code would be like:
const router = useRouter();
useEffect(()=>{
if(!router.isReady) return;
// codes using router.query
}, [router.isReady]);
It's impossible to get the query value during the initial render.
Statically optimized pages are hydrated without the route parameters, so the query is an empty object ({}).
Next.js will populate the query after the page has been hydrated.
Next.js 10.0.5 and up
To determine if the route params are ready, you can use router.isReady inside a useEffect hook. For an example, see the answer provided by #doxylee.
Before Next.js 10.0.5
At first render of a dynamic route router.asPath and router.route are equal. Once query object is available, router.asPath reflects it.
You can rely on the query value within a useEffect hook after asPath has been changed.
const router = useRouter();
useEffect(() => {
if (router.asPath !== router.route) {
// router.query.lang is defined
}
}, [router])
GitHub Issue - Add a "ready" to Router returned by "useRouter"
In NextJS 9+, one way to ensure route parameters are immediately available for page components is to get them from the context arg passed to getServerSideProps() and pass to the component as props.
For a page like [id].js,
export function getServerSideProps(context) {
return {
props: {params: context.params}
};
}
export default ({params}) => {
const {id} = params;
return <div>You opened page with {id}</div>;
};
This is a great question and one that took a few days for me to figure out what the best approach is.
I have personally found three viable solutions to the problem of validating dynamic route path params or even just route path params in general.
The three solutions are
SSR (don't recommend) [Next >= 10]
useRouter
Middleware [Next 12 required]
In my examples a will use a route that requires a reset-token or it should be redirected.
SSR
Firstly server side rending with getServerSideProps.
Vercel recommends to use SSR as a last resort and I would highly recommend not using SSR when able (time to byte & cost).
We suggest trying Incremental Static Generation or Client-side Fetching and see if they fit your needs.
https://vercel.com/blog/nextjs-server-side-rendering-vs-static-generation
But in the case that you do, say there is some server side api validation call you require to validate the query param.
export const getServerSideProps = async (context) => {
const { token } = context.query;
if (!token) {
return {
redirect: {
permanent: false,
destination: "/",
}
}
}
return {
props: {}
// props: { token }
// You could do this either with useRouter or passing props
}
}
useRouter Secondly the easiest useRouter. When I first did this I came across the problem when nextjs/react hydrates there will be a point when the query params are null. Luckily useRouter has isReady!
import Router, { useRouter } from "next/router";
const { query, isReady } = useRouter();
useEffect(() => {
if (!isReady) return;
if (!query.token) {
Router.push("/")
}
}, [isReady])
Middleware now this is my personal favourite as it seperates the functionality in a clean way imo.
I found this based of a vercel example. I would highly recommend reading through a bunch of these to find best practices.
https://github.com/vercel/examples/
import { NextResponse, NextRequest } from 'next/server'
export async function middleware(req) {
const { pathname, searchParams } = req.nextUrl
if (pathname == '/reset-token') {
const index = searchParams.findIndex(x => x.key === "token")
// You could also add token validation here.
if (!index) {
return NextResponse.redirect('/')
}
}
return NextResponse.next()
}
Here is the repo which has some cool filtering of query parameters.
This is a more soft approach instead of hard redirecting.
https://github.com/vercel/examples/tree/main/edge-functions/query-params-filter
Nico also has a great answer on this, expect I wouldn't recommend using hooks like in his example, instead use isReady.
https://stackoverflow.com/a/58182678/4918639
For Class Component Lovers
The even better approach is to listen for a dedicated event for this routeChangeComplete using this.props.router.events.on method, inside componentDidMount if you're using class component -
routeChangeComplete = () => {
// this WILL have valid query data not empty {}
console.log(this.props.router.query);
};
componentDidMount() {
this.props.router.events.on("routeChangeComplete", this.routeChangeComplete);
}
componentWillUnmount() {
this.props.router.events.off("routeChangeComplete", this.routeChangeComplete);
}
Ref: https://nextjs.org/docs/api-reference/next/router#routerevents
routeChangeComplete: Fires when a route changed completely.
Practically when isReady has become true or when router.query object has data.
For NextJS version - 12.0.8
"If you export a function called getServerSideProps (Server-Side Rendering) from a page, Next.js will pre-render this page on each request using the data returned by getServerSideProps."
=async functions
refference:https://nextjs.org/docs/basic-features/data-fetching/get-server-side-props#getserversideprops
Simply putting that async function on the page notifies NextJS of its presence.During prerendering stage of the component, the query object of the router will be empty.
isReady: boolean - Whether the router fields are updated client-side and ready for use. Should only be used inside of useEffect methods and not for conditionally rendering on the server.
refference: https://nextjs.org/docs/api-reference/next/router
solution:
import { useRouter } from 'next/router';
const Fn = () =>{
const router = useRouter();
const { param } = router.query;
const fetchData = async () => {
await fetch();
}
useEffect(() => {
fetchCat();
}, [router.isReady]);
}
I resolved my problem that I need it in Hoc component.
I wrapped using withRouter(withLocale(Comp)) and create conditional in HOC
export default function withLocale(WrappedPage) {
const WithLocale = ({ router, ...props }) => {
const { lang } = router.query;
if (!lang || !isLocale(lang)) {
return <Error statusCode={404} />;
}
return (
<LocaleProvider lang={lang}>
<WrappedPage {...props} />
</LocaleProvider>
);
};
return WithLocale;
}
Next.js <= 10.0.5
This is a good work around, I found around from this comment
Add useQuery.ts helper file
// useQuery.js
import { useRouter } from 'next/router';
// Resolves query or returns null
export default function useQuery() {
const router = useRouter();
const ready = router.asPath !== router.route;
if (!ready) return null;
return router.query;
}
usage
// In your components (instead of useRouter)
const query = useQuery();
useEffect(() => {
if (!query) {
return;
}
console.log('my query exists!!', query);
}, [query]);
Class Component | 12/16/2022 | React JS 18.2.0 | Next JS 13.0.6
I got the answer for those who want to use Class Component. This was actually nowhere to be found ! Enjoy !
You will add if(this.props.router.isReady) and include return in the condition in render().
.
.
import { withRouter } from 'next/router';
import { Component } from 'react';
class User extends Component {
...
render() {
if(this.props.router.isReady){ // Add this condition and include return ()
// Do anything
console.log(this.props.router.query) // Log 'query' on first render
return (
<div>
<SearchBar pid={this.props.router.query.pid} /> // Pass the query params to another component if needed
</div>
);
}
}
}
export default withRouter(User);

Why my console.log is showing 'Undefined' first And Then Display The required number even after i log it after a settimeout of 2 sec {REACT}

I am sending AllmightyUID = 2(for example) from App.js in the User.js component through contextApi ,there is no useEffect in my User component , but when i log the value in my User component it is logged 2 times first time is shows undefined and second time correct data(2) even if i log it after 2- 3 seconds due to this i am unable to make further api calls (i get cannot read the value undefined errors)
solutions i have tried :-
1.) I have removed strict mode from index.js
2.) passed the value as props but still the same problem
import React, { useContext, useState } from 'react'
import { AllMightyUID } from '../App'
import axios from 'axios'
const User = (props) => {
let receivedUID = useContext(AllMightyUID)
const [UID1, setUID1] = useState();
setTimeout(() => {
console.log(receivedUID);
}, 2000);
return(
<></>
)
}
I am sending data from a state variable in App.js
Often, API calls are asynchronous by nature, meaning the rest of the code can execute while the app is still waiting for the API response. Which explains why you get the value when you use the setTimeout function.
You can try to have an if statement that will make other API calls after the UID has been set.
Before rendering it's called that's why you got the error.
You should try to in useEffect and then you solved your issue.
import React, { useContext, useState, useEffect } from 'react'
import { AllMightyUID } from '../App'
import axios from 'axios'
const User = (props) => {
let receivedUID = useContext(AllMightyUID)
const [UID1, setUID1] = useState();
useEffect(() => {
console.log(receivedUID);
}, []);
return(
<></>
)
}

[Unhandled promise rejection: Error: Invalid hook call. Hooks can only be called inside of the body of a function component

Hello I am making a react native app. This is my first react-native project and second project using react. Anyway I am getting this error in my react native project. I am posting my modules please help me.
So this is my module which uploads the profile picture to my express server.
const updateProfilePicture = image => {
try {
console.log("Update profile picture hit");
const { user: token } = useAuth();
console.log(`Token received: ${token}`);
const data = new FormData();
console.log(image);
let fileName = image.split("/");
fileName = fileName[fileName.length-1]
console.log(`File name: ${fileName}`)
let extensionName = fileName.split(".");
extensionName = extensionName[extensionName.length-1];
console.log(`Extension name: ${extensionName}`)
data.append('token', token);
data.append('pimage', {
name: Random.getRandomBytes(8).toString('hex')+"."+extensionName,
type: 'image/'+extensionName,
uri: image
});
console.log(`This is the data\n`+data);
return authClient.post(endpointUpdatePicture, data);
} catch(error) {
console.log("Error in update profile picture", error);
}
};
From hit and try I found that the line const { user: token } = useAuth(); is making it wrong.
Before going forward, useAuth() is my custom hook for tracking down user. user is actually a jwt token.
Here is my useAuth()
import { useContext } from 'react';
import authStorage from './storage';
import AuthContext from './context';
import jwt from 'jwt-decode';
export default useAuth = () => {
const {user, setUser} = useContext(AuthContext);
const { name, rating, number, uri } = jwt(user);
const logout = () => {
setUser(null);
authStorage.removeToken();
}
console.log(`Uri: ${uri}`);
return { user, setUser, logout, name, rating, number, uri };
}
Now I have created a context in my App.js from where I get this user and setUser basically the token. Writing this line is throwing me the hook error.
Please help me in 2 ways:
Please tell me why this error occurs because as you see I have not violated any hook law as I can see.
Please tell me if I am doing it right.
since your updateProfilePicture is not called at your component body, you should change it to receive as param your token.
Then at your Component you can call your hook useAuth at component body, extracting the desired token. This way you can pass it as variable to updateProfilePicture without facing any error, since useAuth will be called correctly at your function body.
your code would look something like:
const updateProfilePicture = (image, token) => {
// ... same code here without 'useAuth'
}
const Component = ({ image }) => {
const { user: token } = useAuth();
const onsubmit = () => updateProfilePicture(img, token)
return (
<>
<div>upload here image</div>
<button onClick={() => onsubmit(image, token)}>upload</button>
</>
)
}
Hooks in react functional components have to be used in the main component function or as a part of custom hooks, without conditions, loops, or callbacks.
You have to move useAuth hook to the main component function, outside try-catch block, and outside updateProfilePicture function.
According to React Documentation
Don’t call Hooks inside loops, conditions, or nested functions. Instead, always use Hooks at the top level of your React function, before any early returns. By following this rule, you ensure that Hooks are called in the same order each time a component renders. That’s what allows React to correctly preserve the state of Hooks between multiple useState and useEffect calls.
✅ Call Hooks from React function components.
✅ Call Hooks from custom Hooks (we’ll learn about them on the next page).
Your useAuth hook is called inside try-catch block. Instead, call it at top-level of the functional component

Categories