react-toastify popup showing 2 times - reactjs

Website error visual on chrome
I create a react website. On this website, I create a social login icon using firebase-hooks. But when I click on the social login button the pop-up shows. But after closing that pop-up I use react toastify to show the error. But always It's showing twice. and can't fix this problem
const SocialLogin = () => {
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || "/";
const [signInWithFacebook, facebookUser, facebookLoading, facebookError] =
useSignInWithFacebook(auth);
facebookError && toast.error(facebookError.message);
const [token] = useToken(facebookUser);
token && navigate(from, { replace: true });
return (
<div>
<div className="or">
<div></div>
OR
<div></div>
</div>
<div className="social-logins">
<p>{facebookLoading && `Loadin Please Wait`}</p>
<div className="social-btn" onClick={() => signInWithFacebook()}>
<SiFacebook />
<span>Facebook</span>
</div>
</div>
<ToastContainer pauseOnHover />
</div>
);
};

toast message will be appeared on every re render , you need to call toast when you get error message from fb , you need to call toast inside of useEffect, something like this
React.useEffect(() => {
if (facebookError.message) {
toast.error(facebookError.message);
}
}, [facebookError.message])

Related

Unwanted delay displaying user name and profile picture in React

I have a web page/app written in React that has two components, main page and a navigation bar at the top of the page. The navigation bar has a Google login button component that allows the user to log in with their Google account. When the user logs in, the navigation bar also has a component that shows the user name and profile picture. Here is an example screenshot:
Imgur
The problem is that when the user navigates to other pages, the avatar and text always take about a second to show up, making the page navigation janky.
When the user navigates to other page, the user avatar and name take a second to show up. This causes everything else on the page to suddenly move downwards.
Here's some parts of the code:
App.js
const App = () => {
return(
<div>
<Navigation/>
<Routes>
<Route path="/" element={<Landing/>} />
<Route path="/extrainfo" element={<ExtraInfo/>} />
<Route path="/test" element={<Test/>}/>
<Route path="/userpage" element={<Userpage/>}/>
</Routes>
</div>
);
}
Navigation.js
const Navigation = () => {
let userInfo = JSON.parse( localStorage.getItem('userInfo') );
const [isLoggedIn, setIsLoggedIn] = useState(false);
const navigate = useNavigate();
const onSuccess = async (googleRes) => {
localStorage.setItem("user", JSON.stringify(googleRes));
setIsLoggedIn(true);
try{
let userResponse = await UserService.getUser()
if(userResponse.status === 200){
setIsLoggedIn(true);
navigate("/userpage");
}
}
catch(error){
if (error.response.status === 404){
/* navigate("/extrainfo"); */
}
const resMessage = (error.response && error.response.data && error.response.data.message) || error.message || error.toString();
console.log(resMessage);
}
};
const onFailure = (err) => {
console.log('failed', err);
};
const onLogout = (res) => {
console.log("log out");
UserService.logout();
setIsLoggedIn(false);
}
useEffect(() => {
document.title = 'Navigation';
const start = () =>{
gapi.client.init({
clientId: process.env.REACT_APP_GOOGLE_CLIENT_ID,
scope: 'email',
});
}
gapi.load('client:auth2', start);
}, []);
return (
<nav className="dt w-100 border-box pa2 ph5-ns bg-#f5f5f5">
<a href="/" title="Home">
<img src="mylogo.png"
className="dib w3 h3 br-100" alt="Site Name"/>
</a>
<div className="dtc v-mid w-40 tr">
{ isLoggedIn ? (
<GoogleLogout
clientId= {process.env.REACT_APP_GOOGLE_CLIENT_ID}
buttonText="Logout"
onLogoutSuccess={onLogout}
/>) : (
<GoogleLogin
clientId= {process.env.REACT_APP_GOOGLE_CLIENT_ID}
buttonText="Sign in"
onSuccess={onSuccess}
onFailure={onFailure}
cookiePolicy={'single_host_origin'}
isSignedIn={true}
/>
)}
</div>
<div className="dtc v-mid w-10 tr">
<a className="link dim white f6 f5-ns dib mr3 mr4-ns bg-dark-gray pa2" href="landing" title="Landing">Enter page</a>
</div>
<MyAvatar isLoggedIn={isLoggedIn}/>
</nav>
);
}
MyAvatar.js
const MyAvatar = (isLoggedIn) => {
const usrData = JSON.parse( localStorage.getItem('user') );
let usrObj = {};
let usrName = null;
let usrImg = null;
if (usrData) {
usrObj = usrData['profileObj'];
usrName = usrObj['name'];
usrImg = usrObj['imageUrl'];
}
if(isLoggedIn.isLoggedIn === true ){
return(
<div className="dtc v-mid w-10 pa1 tc">
<img
src={usrImg}
className="br-100 h3 w3 dib" alt={usrName + ' avatar'}>
</img>
<p className="avatar_name">{usrName}</p>
</div>
)
}
}
it seems like the information tooks a bit longer then the rest to load. Usually if you would use a styling library, you could use skeletons. These elements are like placeholders which are shown until the data is loaded properly. You see them for example in many social media apps, when new content is loading but not displayed yet. But this is a intermediate thing to learn.
What could be more helpful in your case, is to move the loading part of your app from the navigation component into the main App. By this, you prevent a new loading everytime the Navigation element is rendered, which I assume causes the delay. Or, even better would be a function which is only called when someone clicks the login button.
You should have a look at stores also. I assume you're learning the basics, so stores will cross your ways sooner or later, but for your case, they are pretty good, since you can access them from everywhere and don't have to deal with propdrilling.
Just put the Userdata in a store and acess the store in the Navigation element. That should do the trick. Have a nice day and keep on learning.

reactstrap, callback hook used as ref weird behaviour

While trying to get a DOM element's position on render using this code:
const Modes = () => {
const callbackRef = useCallback(domNode => {
if (domNode) {
let rect = domNode.getBoundingClientRect()
console.log("rect", rect)
}
}, []);
return <>
<Toast>
<ToastHeader></ToastHeader>
<ToastBody>
<div ref={callbackRef}> </div>
</ToastBody>
</Toast>
</>
}
I noticed that it always prints a DOMRect object with zero for every property :
If I add state dependence and then state changes causing rerender, the correct position will be printed. Something like this:
const Modes = () => {
const callbackRef = useCallback(domNode => {
if (domNode) {
let rect = domNode.getBoundingClientRect()
console.log("rect", rect)
}
}, []);
const [show, setShow] = useState(true) // added state
return <>
<Toast>
<ToastHeader></ToastHeader>
<ToastBody>
{show ? <div ref={callbackRef}> </div> : null} // div inside Toast can be toggled
</ToastBody>
</Toast>
<Button onClick={() => setShow(!show)} >toggle </Button> // added toggle button
</>
}
After double click on the button:
What confuses me the most is the fact that if I replace this Toast imported from Reactstrap with pure html with bootstrap classes the problem disappears. And this is exactly what React renders because I copied it from source code in the browser:
<div class="toast fade show" role="alert">
<div class="toast-header">
<strong class="me-auto"></strong>
</div>
<div class="toast-body">
<div ref={callbackRef}> </div>
</div>
</div>
And it seems to be a problem that exists just for this Toast component. For Reactrstrap's Card for example it is not the case. So how can using a component which at the end of the day gets rendered into a certain html code be different from using the same html code and why this particular component turns out to be a special case regarding obtaining its DOMRect?

How to render Video Page when the button is clicked before taking the next action in React.js

how can I show a video when the button is clicked and then it performs an
action , so step by step:
user lands to the main page
user clicks on the button that should take him/her to home page
I used useNavigate to change the route of the page to /home, but before doing that, I want the user to see short video.
so far this is what I came up with, but it doesnt work
const Main = (props) => {
let navigate = useNavigate();
const playVideo = () => {
return (
<div>
<video src={video}></video>
</div>
)
}
const handleClickHome = async (event) => {
event.preventDefault();
await playVideo()
return (
navigate("/home")
)
}
return (
<div className={classes.main} >
<button onClick={handleClickHome} className={classes.button}> <h2> LET ME IN </h2> </button>
</div >
);
}
export default Main ```
You can show your video by clicking the button and use under below event for navigation.
document.getElementById('videoId').addEventListener('ended',myHandler,false);
function myHandler(e) {
// do navigation
}

disable a function on state change

i want to disable/enable a function, depends on state.
the problem is, i have this function that create some css effect,
which works only in .
it takes the DIV that classNamed "glass" and does some stuff.
this div appears only in , but NOT on Homepage2.
so what happens is when i change state to view Homepage2, i get this:
TypeError: Cannot read property 'style' of null.
so im guessing i need to stop the function?
the App
function App() {
const Theme = useSelector(state => state.ThemeReducer);
return (
<div className="App">
{Theme === "Theme1" &&
<Homepage />
}
{Theme === "Theme2" &&
<Homepage2 />
}
</div>
);
}
Homepage
const Homepage1 () => {
//this is the function i want to stop/start depends on state
document.addEventListener("mousemove", function(e){
const glass = document.querySelector(".glass");
glass.style.left = e.offsetX + "px";
glass.style.top = e.offsetY + "px";
// dont get too much into this function its not importent
return(
<div className="glass" />
<h1>this is HOMEPAGE 1</h1>
<button>this button changing theme with redux</button>
)
hompage 2
const Homepage2 = () => (
<div> homepage 2 </div>
<button>this button changing theme with redux</button>
)
If you want to exit the mousemove handler if glass is null then simply check that condition:
if (!glass) {
return;
}

React - Browser's Back button doesn't work

In the following component, if I click on any of the two buttons, the URL in the address-bar gets changed.
In the list view if you click on the button Details the page get rendered and shows that particular item and the URL in the address bar get changed too.
And in the user view if you click on the "Back to overview" button, the page renders back to the list view and the URL gets changed again.
import React, { useState, useEffect, Fragment } from 'react'
import axios from 'axios'
const UserList = ({ id, setID }) => {
const [resources, setResources] = useState([])
const fetchResource = async () => {
const response = await axios.get(
'https://api.randomuser.me'
)
setResources(response.data.results)
}
useEffect(() => {
fetchResource()
}, [])
const renderItem = (item, userId) => {
const setURL = (e) => {
window.history.pushState(null, null, '/' + e)
setID(item.login.uuid)
}
const clearURL = (e) => {
window.history.back()
setID(null)
}
return (
<Fragment key={item.login.uuid}>
{userId ? (
// User view
<div>
<img src={item.picture.large} />
<h2>
{item.name.first}
</h2>
<p>
{item.phone}
<br />
{item.email}
</p>
<button onClick={() => clearURL('/')}>
Back to overview
</button>
</div>
) : (
// List view
<li>
<img src={item.picture.large} />
<h2>
{item.name.first}
</h2>
<button onClick={() => setURL(item.login.uuid)}>
Details
</button>
</li>
)}
</Fragment>
)
}
const user = resources.find(user => user.login.uuid === id)
if (user) {
// User view
return <div>{renderItem(user, true)}</div>
} else {
// List view
return (
<>
<ul>
{resources.map(user => renderItem(user, false))}
</ul>
</>
)
}
}
export default UserList
Everything is working fine.
However, the problem with this solution is that on user view, I cannot use the browsers back button to go back to the list view page.
Is there any way I can change this without using React Route?
So what I believe is happening is you are over-writing the 'history' of the browser. The 'history' is pretty much just a stack of paths you've been and when you click the back button it just pops the current path off the stack. I think that when your using 'window.history.pushState(null, null, '/' + e)' its setting the history = to null so there is nothing to go back to. I would recommend using react-router and just pushing a path ie. router.push('/whatever'). There are a bunch of ways to interact with the history through react without using the native history object. If you want to use the native history object https://developer.mozilla.org/en-US/docs/Web/API/History_API
Edit - I apologize your not overwritting the history, but I do still believe that the error is coming from passing a 'null' value as the 'state' param for the pushState method

Resources