How to to be displayed reactour just first time in nextjs? - reactjs

I'm using reactour in next.js
I want to just first time when page is rendered reactor to be displayed, and when route change and come back to this page reactor not to be displayed
how can do this?
this is how I call it
import { disableBodyScroll, enableBodyScroll } from "body-scroll-lock";
import dynamic from "next/dynamic";
const Tour = dynamic(() => import("reactour"), { ssr: false });
const tourConfig = [
{
selector: ".step_1",
content:
'Click "View future forecast earning" to look at all....',
},
{
selector: ".step_2",
content:
"Chose different earning forecasts to see how your property...",
},
];
export default function MyPage(props) {
const disableBody = target => disableBodyScroll(target);
const enableBody = target => enableBodyScroll(target);
const [isTourOpen, setIsTourOpen] = useState(false);
const closeTour = () => setIsTourOpen(false);
useEffect(() => {
const timing = setTimeout(() => {
setIsTourOpen(true);
}, 2000);
return () => {
clearTimeout(timing);
};
}, []);
return (
<>
<OtherComponent />
<Tour
onRequestClose={closeTour}
steps={tourConfig}
isOpen={isTourOpen}
rounded={5}
onAfterOpen={disableBody}
onBeforeClose={enableBody}
className={classes.root}
disableInteraction
inViewThreshold={50}
/>
</>
);
}

This entirely depends on your logic you can do this in 3 ways if you like:
The local storage way:
localStorage.setItem('displayTour', true);
If you're not clearing out the local storage then you can always check your storage whenever the user signs in to check (in useEffect) if the tour is displayed to them or not.
Storing in cookies:
You can always set cookies for the first time the user signs in and check, but this approach has a con, cookies are set in the browser so if the user has already gone through the tour and they sign in from another browser the tour will be rendered again.
Tour Flag from API (Network Request):
This may be the right thing to do if you are not trying to save your network requests. You can always send back a flag from backend e.g is_tour_displyed: false and can always validate whether to show the tour or not.
Note: The localStorage and the cookies may be cleared out anytime, considering if that's not a problem for you. You can always go for the third option.

you can make condition and add a value to localStorage like blow:
localStorage.setItem('playTour', 'true');
and when ever you played the tour at first time you can set this value to false

Related

My react component never displays the information from the database

I have a small web app displays game information.
I am using React hooks so that the component is modern.
When this component loads, I want it to connect to the api via axios, and get the description of the game.
But when it loads, the value inside the <GameVault /> is always null.
When I look in the database, it is not null. If I hit the api directly, it does return the game description.
My console.log is hit twice for some reason. The first time it's null, the second time it has the needed value.
I am also not getting any errors, so I don't know why this isn't working.
Here is the code:
const Vault = ({ game }) => {
const [gameText, setGameText] = useState(null);
async function fetchGameText() {
const response = await axios.get(`/api/gamermag/${game.id}/gameDescriptionText`);
setGameText(response.data);
}
useEffect(() => {
fetchGameText();
}, []);
console.log("gameText: ", gameText);
const gamerValue = useMemo(() => {
return gameText ? gameText : "";
}, [gameText]);
return (
<GameVault value={gamerValue} />
)
}
export default Vault;
Is there a way to get this to work?
Thanks!
You need to wait for the data to load from the server. While the data is being fetched, gameText will be null and when it's done fetching, it stores the response. That is why your console.log hit twice. The first time is the component's first render, and the second time is when the gameText changes its state which caused a rerender.
You need to add logic to wait for the data.
if(!gameText){
return <div>loading...</div>
}

How can I stay the user in the same page?

Every time I reload the my account page, it will go to the log in page for a while and will directed to the Logged in Homepage. How can I stay on the same even after refreshing the page?
I'm just practicing reactjs and I think this is the code that's causing this redirecting to log-in then to home
//if the currentUser is signed in in the application
export const getCurrentUser = () => {
return new Promise((resolve, reject) => {
const unsubscribe = auth.onAuthStateChanged(userAuth => {
unsubscribe();
resolve(userAuth); //this tell us if the user is signed in with the application or not
}, reject);
})
};
.....
import {useEffect} from 'react';
import { useSelector } from 'react-redux';
const mapState = ({ user }) => ({
currentUser: user.currentUser
});
//custom hook
const useAuth = props => {
//get that value, if the current user is null, meaning the user is not logged in
// if they want to access the page, they need to be redirected in a way to log in
const { currentUser } = useSelector(mapState);
useEffect(() => {
//checks if the current user is null
if(!currentUser){
//redirect the user to the log in page
//we have access to history because of withRoute in withAuth.js
props.history.push('/login');
}
// eslint-disable-next-line react-hooks/exhaustive-deps
},[currentUser]); //whenever currentUser changes, it will run this code
return currentUser;
};
export default useAuth;
You can make use of local storage as previously mentioned in the comments:
When user logs in
localStorage.setItem('currentUserLogged', true);
And before if(!currentUser)
var currentUser = localStorage.getItem('currentUserLogged');
Please have a look into the following example
Otherwise I recommend you to take a look into Redux Subscribers where you can persist states like so:
store.subscribe(() => {
// store state
})
There are two ways through which you can authenticate your application by using local storage.
The first one is :
set a token value in local storage at the time of logging into your application
localStorage.setItem("auth_token", "any random generated token or any value");
you can use the componentDidMount() method. This method runs on the mounting of any component. you can check here if the value stored in local storage is present or not if it is present it means the user is logged in and can access your page and if not you can redirect the user to the login page.
componentDidMount = () => { if(!localStorage.getItem("auth_token")){ // redirect to login page } }
The second option to authenticate your application by making guards. You can create auth-guards and integrate those guards on your routes. Those guards will check the requirement before rendering each route. It will make your code clean and you do not need to put auth check on every component like the first option.
There are many other ways too for eg. if you are using redux you can use Persist storage or redux store for storing the value but more secure and easy to use.

React Redux, load data from the API on first page load ONLY. Render component once data is loaded

I am DEFINITELY doing something wrong at the core of my app.
I think its where I am making a request to my API. I'm also not happy with the firstLoad flagging to tell the app to call the API.
I am using React/Redux - building from this boiler plate https://www.npmjs.com/package/create-react-app-redux.
It uses mapStateToProps, mapDispatchToProps and connect to glue everything together.
So I have a component called "Shop"
// only true when user first visits url OR presses F5 to refresh.
// Its conveniently false when page rerenders
var firstLoad = true;
const Shop = ({ stateProps, dispatchProps }) => {
if(firstLoad) {
firstLoad = false;
// dispatchProps contains a method called changeState that will update state.shops to the result from the API. It will also set state.loading to true while calling and false when finished.
// Note, I am not modifying state directly. The dispatchProps wraps the action that does so
server.GetShops({url: "api/shops", updateField:"shops", loading:true, token:"abc-xyz"}, dispatchProps);
}
if(stateProps.loading) {
return (
<div>loading...</div>
);
}
var shopUrl = window.location.href; // extract the part of the url after the domain
var selectedShop = stateProps.shops.find(s => {
return s.url === shopUrl;
});
if(!selectedShop) {
window.location.href = "/";
}
return (
<div>
{selectedShop.welcomeMessage}
</div>
);
}
The problem im having is I have to refresh TWICE to see when the welcomeMessage is changed.
So if its originally "hello world" from the database and I change it to "hello UK" in the database.
When I refresh the page, i expect the app to fetch data and display loading.
When it finished fetching data, a re-render occurs and it should show Hello UK in the welcome message.
However this doesn't happen until the second page refresh.
Does what I described make sense to anyone?
You are not making any change based on the value of selectedShop
you should keep the value of selectedShop in a local state variable
const [ selectedShop , setSelectedShop ] = useState({});
then whenever the value is changed from api call update the local state value
useEffect( () => {
var selectedShop = stateProps.shops.find(s => {
return s.url === shopUrl;
});
setSelectedShop(selectedShop);
} , [stateProps.shops])
now when the value changes in stateProps it will update the local state value and trigger a re render .

Managing exit of a user from a game 'room' on React?

This might seem complicated - I am working on a game app on React that involves users all joining a certain <Route> in my project. When all users are on this route, the game is unpaused and if not the game is paused.
My question is: How can I manage to suddenly pause the game if a user leaves the link or closes the tab ? Is there any way to actively check this on react? I figured useEffect hook might be useful but I don't know how to get the number of users leaving a site or closing the tab in real-time at once.
Here is some basic code to understand what I want. I have a functional React component <GameSession> that hosts a game when users join this link:
const GameSession = ({userRegistered}) =>{
const [paused, setPaused] = useState(false);
useEffect(() => {
// store some user related data in localStorage when the user loads
}, []);
useEffect(() => {
setPaused(numberofUsersInGame === totalUsers ? false : true)
}, [numberofUsersInGame]);
/* MY PROBLEM IS IN THIS EFFECT HOOK ABOVE. HOW TO CHECK IF A USER HAS LEFT THIS
COMPONENT OR PAGE SO I CAN UPDATE numberofUsersInGame ? */
if(!userRegistered)
return <Redirect to="/dashboardpage">
if(paused)
return <PausedComponent /> /*this component should fire a return when total
number of users registered to this game is not
equal to current number of users who are
active on the GameSession component (this link)*/
return (
<Fragment>
<GameComponent>
</Fragment>
);
};
GameSession.propTypes = {
// PropTypes go here
};
const mapStateToProps = (state) => ({
//states go here
});
export default connect(mapStateToProps, mapDispatchToProps)(GameSession);

Strategy to overcome caching of Axios requests?

I've noticed that if I make a GET call to the same API endpoint twice in a row then the previous result appears to get cached. This is causing a problem for the logic of my React component which is a multi-page Wizard.
I define my API request like this:
const [{ data, isLoading, isError }, userNameDoFetch] = useFetch(
null,
{ }
)
The user can then enter a username into an input element and its existence is checked liked this:
const handleBlur = (event) => {
const propName = event.target.name;
const propValue = event.target.value;
if (propValue.length > 0) {
setIsFetching(true);
userNameDoFetch( `${API_ROOT()}account_management/users/name/${propValue}` );
}
}
}
I then have a useEffect that processes the data coming back from the server. It begins like this:
useEffect(() => {
setIsFetching(false);
...
The problem is that the useEffect isn't called if say, the user tabs back into the Username field and then tabs out again. This sets isFetching to true, which disables the Next button in my wizard, leaving the user trapped on that page.
Any thoughts on how to resolve this?

Resources