I'm using the npm module aws-cognito-next to implement authentication for one of my app. There the function getServerSideAuth(context.req); seems to not working as expected:
export async function getServerSideProps(context) {
// getServerSideAuth will parse the cookie
const initialAuth = getServerSideAuth(context.req);
return { props: { initialAuth } };
}
Then in the same page which is Home (/pages/home.js) I use this returned initialAuth as follows:
const Register = ( {initialAuth} ) => {
console.log("initialAuth is: " + util.inspect(initialAuth))
const auth = useAuth(initialAuth);
...
//other logic
...
}
But I get out put as: initialAuth is: null. So why doesn't initialAuth isn't getting returned from serverside? What am I doing wrong here?
getServerSideAuth checks to see if user is logged in and returns tokens that can be used in useAuth. You can check for null and add logic to send the user to the login/logout pages.
const Register = ( {initialAuth} ) => {
const auth = useAuth(initialAuth);
const { login, logout } = useAuthFunctions();
return (
<React.Fragment>
{auth ? (
<button type="button" onClick={() => logout()}>
sign out
</button>
) : (
<React.Fragment>
<button type="button" onClick={() => login()}>
sign in
</button>
</React.Fragment>
)}
</React.Fragment>
);
}
For more information on useAUth see here.
Related
I want to use react-firebase-hooks for firestore, but I cant seem to make it work properly, I have collection of users and it has subcollection of budgets. If user is logged in I want to show his budgets. My code:
The problem is mainly in useCollection hook, where I need to pass user.uid, but user is undefined in the beginning. How else should I do this?
const Homepage = () => {
const [user, loading, error] = useAuthState(auth);
const [showAddBudgetModal, setShowAddBudgetModal] = useState(false);
const [value, dataLoading, dataError] = useCollection(collection(db, `users/${user!.uid}/budgets`), {
snapshotListenOptions: { includeMetadataChanges: true },
});
const [showAddExpenseModal, setShowAddExpenseModal] = useState(false);
const [addExpenseModalBudgetId, setAddExpenseModalBudgetId] = useState('');
const openAddExpenseModal = (budgetId?: any) => {
setShowAddExpenseModal(true);
setAddExpenseModalBudgetId(budgetId);
};
if (loading) {
return (
<div>
<p>Initialising User...</p>
</div>
);
}
if (error) {
return (
<div>
<p>Error: {error.message}</p>
</div>
);
}
if (user) {
return (
<div>
<h1>Welcome {user.displayName}!</h1>
<button onClick={logOut}>Logout</button>
<div className="buttons">
<button onClick={() => setShowAddBudgetModal(true)}>Add budget</button>
</div>
<AddBudgetModal show={showAddBudgetModal} onClose={() => setShowAddBudgetModal(false)}></AddBudgetModal>
<div>
{dataError && <strong>Error: {JSON.stringify(error)}</strong>}
{dataLoading && <span>Collection: Loading...</span>}
{value && user && (
<div>
{value.docs.map((budget) => (
<BudgetCard
key={budget.id}
name={budget.name}
max={budget.max}
onAddExpenseClick={() => openAddExpenseModal(budget.id)}
onViewExpensesClick={() => openAddExpenseModal(budget.id)}
></BudgetCard>
))}
</div>
)}
</div>
</div>
);
}
};
export default Homepage;
There are 2 ways to solve this problem in my opinion
First one is to use optional chaining to check whether the user exist or not eg:
const [value, dataLoading, dataError] = useCollection(user && query(
collection(getFirestore(app), "users", user.uid, "budgets"), {
snapshotListenOptions: {
includeMetadataChanges: true
},
});
For more information about this there is a similar thread about this issue.
Second way is to use useEffect hook to implement the same like this:
useEffect(() => {
if (user) {
const [value, dataLoading, dataError] = useCollection(user && query(
collection(getFirestore(app), "users", user.uid, "budgets"), {
snapshotListenOptions: {
includeMetadataChanges: true
},
});
}
}, [user]);
In this way your user can only be rendered if and only if data related to the user is loaded already, but make sure in future to not set user in useEffect as it will create an infinite loop as useEffect has provided user in dependencies array.
For more about usEffect you can go through this documentations
hi , i have this kind of problem .. in my code i should pass the User name dynamicaly
here is my DashBoard wher i should pass the user name like "welcome ,UserName"
const Dashboard = ({logoutUser, user}) => {
const history = useHistory();
console.log("Dashboard user", user)
//here in console i can see the username that i pass
return (
<StyledFromArea bg={colors.dark2}>
<StyledTitle size={65}>Welcome : {user.name }
{ console.log("user.name", user.name)}
</StyledTitle>
{ // but here in console returning undefined , why? }
<Userinfo/>
<ButtonGroup>
<StyledButton to="#" onClick={() => logoutUser(history)}>Logout</StyledButton>
</ButtonGroup>
</StyledFromArea>
</div>
)
}
const mapStateToProps = ({session}) => ({
user: session.user,
});
export default connect(mapStateToProps, {logoutUser})(Dashboard)
//in logout acton i just deleting the sessionService.deleteSession()
//sessionService.deleteUser() and redirect to the home page
I am new to React and trying to set up a basic client-side session. I am getting an error when I am trying to retrieve the username from the local storage. SyntaxError: Unexpected token p in JSON at position 0 Do you have some suggestions on to to fix it?
NavBar.js
const username = JSON.parse(localStorage.getItem('username'));
const NavBar = props => {
if (props.isAuth !== null) {
return <div>
## here I am trying to display the username
<p>Logged In as {{username}}</p>
</div>;
} else {
return <span>Not logged in</span>;
}
};
export default NavBar;
App.js
function App() {
const [loggedIn, setLoggedIn] = useState(localStorage.getItem("token"));
return (
<div>
<Router>
<Navbar isAuth={loggedIn} />
</Router>
<div>
<button
onClick={() => {
if (loggedIn) {
localStorage.removeItem("token", null);
setLoggedIn(null);
} else {
localStorage.setItem("token", true);
localStorage.setItem("username", "pierre-alex");
setLoggedIn(true);
}
}}
value="toggle"
>
Toggle
</button>
</div>
</div>
);
}
export default App;
thank you
If the value of username is an object then we need to stringify it while storing it in localStorage. We can then parse it to get the data.
localStorage.setItem('username',JSON.stringify({name:'Jonh Doe'}));
const username = JSON.parse(localStorage.getItem('username');
If the value stored in localStorage is not an object then we don't need to parse it. We can access it like below.
const username = localStorage.getItem('username')
So i've basically got 2 components on my page.
First is the search component where the users need to type their username and second one where their stats get displayed
and here is my API request call in App.js
useEffect(()=>{
const fetchStats = async ()=> {
const result = await axios.get(`https://cors-anywhere.herokuapp.com/https://public-api.tracker.gg/v2/csgo/standard/profile/steam/${username}`,
{
headers: {
'TRN-Api-Key' : '***************************',
}
}
)
if(username !== null){
console.log(result.data)
setStats(result.data)
}
}
fetchStats()
},[username])
and this is the search component
const Search = ({setInputText, setUsername, inputText, username}) => {
const inputHandler = (e)=> {
setInputText(e.target.value)
}
const searchHandler = (e)=> {
e.preventDefault()
setUsername(inputText)
}
return (
<div>
<form>
<input value={inputText} onChange={inputHandler} type="text"/>
<button onClick={searchHandler}>Search</button>
</form>
</div>
)
}
What i'm having an issue with is when i click a button in the username component the value(username) from the form gets stored in the 'username' state in App.js. Now i'm using this code in the stats component.
const Stats = ({stats}) => {
return (
<div>
<h1>{stats.data.platformInfo.platformUserHandle}</h1>
</div>
)
}
export default Stats
Here stats.data.platformInfo.platformUserHandle doesn't exist when the app starts so it gives me a LOT of errors. How do i keep the app from crashing till the user has input something and data can be sent to the stats component?
im trying to show a button everytime a string is hovered, what im doing is working fine, but when i hover the string it will show every button in available string, i tried to pass the key but it still wont work, here is my code
const _showButton = () => {
setButton(true);
};
const _hideButton = () => {
setButton(false);
};
const _options = (uid) => {
return isButton ? <button key={uid}> ... </button> : null;
};
return(
{isProject.map((p) => {
return (
<div>
<Typography onMouseEnter={_showButton} onMouseLeave={_hideButton}>
{p.title} {_options(p.uid)}
</Typography>
</div>
);
})}
)
any help will be appreciated, thanks before, i know this question might be already asked before but i cant find the one that use a functional like me instead a class
it seems like button state is only one boolean, who controlled all mapped elements.
So you have two options,
First, change button state to an array
const [ button, setButton ] = useState(Array.from({ length: isProject.length }, _ => false))
and pass the index to functions and use specific slot to determine if a button should be visible
const _toggleButton = (i) => {
setButton(prev => prev.map((bool, idx) => i == idx ? !bool : bool);
};
const _options = (uid, i) => {
return button[i] ? <button key={uid}> ... </button> : null;
};
return(
{isProject.map((p, i) => {
return (
<div>
<Typography onMouseEnter={()=>_toggleButton(i)} onMouseLeave={()=>_toggleButton(i)}>
{p.title} {_options(p.uid, i)}
</Typography>
</div>
);
})}
)
Second is refactor mapped elemto it own component and declare state there, that way each elem will have it own state
{isProject.map((p) => <Component p={p} /> )}
function Component({p}) {
const [button, setButton] = useState(false)
const _showButton = () => {
setButton(true);
};
const _hideButton = () => {
setButton(false);
};
const _options = (uid) => {
return button ? <button key={uid}> ... </button> : null;
};
return (
<div>
<Typography onMouseEnter={_showButton} onMouseLeave={_hideButton}>
{p.title} {_options(p.uid)}
</Typography>
</div>
);
}
This is because _option runs in map and iterate over the whole list and the state is a single state which enables it for every item. You should consider setting "p's uid" in state variable (instead of true/false) and compare uid with the one is state in "_options" method.
const [selectedButtonUid, setSelectedButtonUid] = useState('');
const _showButton = (uid) => {
setSelectedButtonUid(uid);
};
const _hideButton = () => {
setSelectedButtonUid('');
};
const _options = (uid) => {
return selectedButtonUid === uid ? <button key={uid}> ... </button> : null;
};
return(
{isProject.map((p) => {
return (
<div>
<Typography onMouseEnter={()={_showButton(p.uid)}} onMouseLeave={_hideButton}>
{p.title} {_options(p.uid)}
</Typography>
</div>
);
})}
)