Firebase auth resets when I refresh a different Route path - javascript

App.js
class App extends Component {
constructor(props) {
super(props);
this.state = {
user: {},
}
}
render() {
return (
<BrowserRouter>
<div style={{background:'floralwhite'}}>
<Route path='/' component={Home} />
<Route path='/calendar' component={Calendar} />
<Route path='/config' component={UserConfig} />
<Route path='/login' component={Login} />
</div>
</BrowserRouter>
);
}
}
I am using react-router-dom Route to create different paths in my web app. And I use these paths in my navbar that renders like this:
render() {
return(
<div className="navbar">
<div className="logo-container">
<img src={Logo}></img>
</div>
<div className="left-link-container">
</div>
<div className="right-link-container">
<span style={{color:'white'}} onClick={this.handleLogout}>Sign Out</span>
<Link style={{ textDecoration: 'none' }} to="/config"><span style={{color:'white', marginRight:'2em'}}>Configuration</span></Link>
<Link style={{ textDecoration: 'none' }} to="/calendar"><span style={{color:'white', marginRight:'2em'}}>Calendar</span></Link>
</div>
</div>
);
}
So, clicking the Calender would lead me to the /calendar path. There is no problem and everything works as intended. However, when I refresh on the /calendar page, it somehow logs off from my firebase authentication.
My authentication happens in my Home component as follows:
class Home extends Component {
constructor(props) {
super(props);
this.state = {
user: {},
}
}
componentDidMount() {
this.authListener();
}
authListener() {
fire.auth().onAuthStateChanged((user) => {
console.log(user);
if (user) {
this.setState({ user });
localStorage.setItem('user', user.uid);
} else {
this.setState({ user: null });
localStorage.removeItem('user')
}
});
}
render() {
return (
<div className="App">
{this.state.user ? (
<div>
<Navbar />
</div>) :
(<Login />)}
</div>
)
};
I do conditionally render the component and lead the user to the Login page when it's not logged on. It auto logs the user off when I refresh from other paths defined in my App.js. I need to fix this because I used fire.auth().currentUser.uid to get the uid of the user in other components with a different path.
Any help?

Check the following pages.
I think to use a React HOOKS is better.
use a React HOOKS
Firebase + React HOOKS Authentication Tutorial
https://www.youtube.com/watch?v=K_wZCW6wXIo
use a higher-order component
A Firebase in React Tutorial for Beginners [2019]
https://www.robinwieruch.de/complete-firebase-authentication-react-tutorial/#firebase-authentication

Related

how to pass data between routes in react

I have a signup page signup.js after successful sign in I need to take those data to another route view sign in details page if I render sign in details then I am viewing it in the same page how to take it to another route ??If I do through window.name after refresh I couldn't view the data[my page layout]
1st page
class Validation extends Component {
constructor(props) {
super(props);
this.validate = this.validate.bind(this);
}
validate(detail,number) {
//i need to take this number to view page
});
}
render() {
return (
<div>
<SignupForm onAddDetail={this.validate} />
</div>);
}
}
export default Validation;
2nd page
class DetailsComponent extends Component {
render() {
let DetailNodes = this.props.details.map(detail =>
(
<Register key={detail.id}
emailId={detail.emailId} password={detail.password}
firstName={detail.firstName} lastName={detail.lastName}
location={detail.location} mobileNumber={detail.mobileNumber}>
</Register>
)
);
return (
<div> <br></br><br></br><br></br><br></br>
{DetailNodes[number-1]}//I need that number from 1st page and carried here
<br/>
</div>);
}
}
route.js
my route page
<Route path="/signup" component={Validation}/>
<Route path="/view" component={DetailsComponent} />
As option you can do it like this:
add field to state
success: true | false
and if signup is successfull
setState({success: true})
and in signup component add ternary
import {Redirect} from 'react-router-dom';
!success ? <SignUp /> : <Redirect to={{
pathname: '/view',
state: {data: signUpCredentials}
}}
/>
and in View component you can access it in
{props.location.state}
You can use the useHistory() hook of React router.
For eg:
const history = useHistory();
...
history.push('/');
You can pass props from Route render. You can do this in multiple ways. If your data is available at router level. Like below. Or setup up a Store for shared data
const myProps = {x,y,z}
<Route path="/signup" render={()=> <Validation myNewProp='someprop' />} />
<Route path="/view" render={()=> <DetailsComponent {...myProps} />} />

React Router: state variable updated with setState not being passed down to Route correctly

So, I have the following problem:
I want to allow users to set the language of my portfolio. To do so, I provide them with two links in the initial <Language /> component, which set the state of <App /> and then lead the user to the home screen - <Home />. The problem is, the updated this.state.language is not passed down to <Home />; instead, the initial value it had is passed down.
My code:
// <App /> component
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
language: "none"
}
}
changeLanguage = event => {
event.preventDefault()
this.setState({ language: event.target.id }, () => {
window.location.href = "/home"
})
}
render() {
return (
<BrowserRouter>
<div id="app">
<Route
exact
path="/"
render={() => (
<Language changeLanguage={this.changeLanguage} />
)}
/>
<Route
path="/home"
component={() => {
return <Home language={this.state.language} />
}}
/>
<Route
path="/about"
render={() => {
return <About language={this.state.language} />
}}
/>
<Route
path="/projects"
render={() => {
return <Projects language={this.state.language} />
}}
/>
<Route
path="/contact"
render={() => {
return <Contact language={this.state.language} />
}}
/>
</div>
</BrowserRouter>
)
}
}
// <Language /> component
const Language = props => {
return (
<div id="language">
<h1>Choose your language.</h1>
<div className="lang-options">
<a
href="/home"
className="lang-link"
id="pt_BR"
onClick={props.changeLanguage}
title="Português Brasileiro"
>
<img
src="https://s3-sa-east-1.amazonaws.com/myhostedfiles.raulf/Images/svg-icons/brazil-flag.svg"
alt="A bandeira brasileira. Clique para ter acesso ao site em português."
/>
</a>
<a
href="/home"
className="lang-link"
id="en_US"
onClick={props.changeLanguage}
title="American English"
>
<img
src="https://s3-sa-east-1.amazonaws.com/myhostedfiles.raulf/Images/svg-icons/usa-flag.svg"
alt="The american flag. Click to access the site in english."
/>
</a>
</div>
<h1>Escolha seu idioma.</h1>
</div>
)
}
// <Home /> component
const Home = (props) => {
console.log(props.language)
return (
<div id="home">
<div className="bg-filter" />
<Navbar />
<TypedIntro />
<LinkBox />
</div>
)
}
When the <Home /> component is loaded, console.log(props.language) logs none to the console, which is the initial value this.state.language is set to. Can anybody explain to me why won't it update, and how to fix it?
Setting window.location.href is going to refresh the page. That will lose all your state. Change your <a> tags to use the react-router <Link to="/home"> tag instead.
Here's a CodeSandbox to help illustrate what is going on:
Have you tried exploring this as a solution? You would have a file where you define your keys to each language and pass around an i18n object to access each key. This is an anti-pattern as you are trying to mutate state with multiple components.
You were having issues because you were using windows.location.href it will refresh the app. And after that you will get a new instance of the app and you will lose the state of the app. And it was the reason you were getting initial state in console.
Change windows.location.href to this.props.history.push() but to do so you need to wrap App component with withRouter HOC from 'react-router-dom'. I have changed your code in some places check that out. And try to use Link tag instead of a tag.
import { BrowserRouter , Route, withRouter} from "react-router-dom";
.....
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
language: "none"
}
}
changeLanguage = event => {
event.preventDefault()
// react-router passes "history" as props
this.setState({ language: event.target.id }, () => this.props.history.push('/home'))
}
render() {
return (
<div id="app">
<Route
exact
path="/"
render={() => (
<Language changeLanguage={this.changeLanguage} />
)}
/>
<Route
path="/home"
component={() => {
return <Home language={this.state.language} />
}}
/>
</div>
)
}
}
// wrapping App component with "withRouter" HOC
const RouterApp = withRouter(App)
// <NewApp /> Component
// you need to do this because component wrapped inside
// "withRouter" HOC must be inside "Router" component
const NewApp = () => {
return <BrowserRouter>
<RouterApp />
</BrowserRouter>
}
// <Language/> Component
const Language = props => {
return (
<div id="language">
<h1>Choose your language.</h1>
<div className="lang-options">
<p
className="lang-link"
id="pt_BR"
onClick={props.changeLanguage}
title="Português Brasileiro"
>
Português
</p>
<p
className="lang-link"
id="en_US"
onClick={props.changeLanguage}
title="American English"
>
American
</p>
</div>
<h1>Escolha seu idioma.</h1>
</div>
)
}
// <Home Component/>
const Home = (props) => {
console.log(props.language)
return (
<div id="home">
Home Component
<p>Language: {props.language}</p>
</div>
)
}
// render NewApp component
ReactDOM.render(<NewApp />, document.getElementById('root'));
You should use <Link to='/home'> instead of window.location.href = "/home".
This will reload the page and reload the component. Also it disables react's capability as a SPA.

Rendering conditional route, when mapping components

I have an application, where I map some sample user components. I add some props, and I want to make a conditional nav link, that renders just a simple "profile components that show the name.
So far I have made a conditional nav, link inside the component, and the props get send correctly, and it displays the paragraph under my User component, but I want to make it redirect, so it only shows the Profile component.
Is there a way so it only shows that component. I tried with the switch but I realized, that it only renders the first, route, so everything else, will still be shown...
render() {
let persons= this.state.persons.map((item, index) =>{
return(
<Router>
<User key={index} name={item.name} img={item.img} id={item.id} />
</Router>
)
})
//user component
render(){
console.log(this.props.name)
return(
<Switch>
<div >
<img src={this.props.img} alt="profile" style={{float: 'left'}}>
</img>
<p style={{textAlign: 'center'}}>{this.props.name}</p>
<p>It's here={this.props.loggedInProp}</p>
<Route path="/:username" exact component={ Profile} />
<NavLink to={`/${this.props.name}`}>Click me</NavLink>
</div>
</Switch>
//Profile component
const Profile= ({match}) =>{
return(
<div>
<p>Hello {match.params.username}</p>
</div>
)
}
<Route
exact
path="/profile/view/:username"
render={props => <ProfileView {...props} />}
/>
inside of ProfileView component you could then use this.props.match.params.username to filter your collection of data and display only it's details.
ProfileView component
import React, { Component } from 'react';
export class ProfileView extends Component {
constructor(){
super()
this.state = {
allUsers[{ user1 ... }, {user2 ...}, ...],
selectedUser: {}
}
}
componentDidMount(){
// fetch('/get/users/from/somewhere').then(users => {
// this.setState({allUsers: users}) // Usually you would just pull your one user from the route and then fetch it's single details from a database
// })
this.setState({selectedUser: allUsers.filter(user => user.username === this.props.match.params.username)})
}
render() {
return (
<div>
<em>Do stuff with your this.state.selectedUser... things here</em>
</div>
);
}
}

Implementing PrivateRoute in React.js

I'm having some problems with implementing PrivateRoute in React. Here is my code:
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentUser: null,
loadingUser: true
}
}
componentDidMount() {
this.onAuth();
};
onAuth = () => {
getCurrentUser().then((json) => {
console.log(json);
this.setState({
currentUser: json,
loadingUser: false
})
}).catch((error) => {
this.setState({
currentUser: null,
loadingUser: false,
})
})
};
logout = () => {
logout();
this.setState({
currentUser: null,
loadingUser: false
});
this.props.history.push("/");
toast.info("Succesfully logout.");
};
render() {
return (
<div className="body">
<ToastContainer closeOnClick={false}/>
<ApplicationHeader currentUser={this.state.currentUser} logout={this.logout}/>
<Grid>
<div className="app-content">
<Switch>
<Route exact path="/vote/:id" render={(props) => <Vote currentUser={this.state.currentUser} {...props}/>}/>
<Route exact path="/login" render={() => <Login onAuth={this.onAuth} />}/>
<PrivateRoute authed={this.state.currentUser != null} exact path="/vote" component={NewProcess} />
<PrivateRoute authed={this.state.currentUser != null} exact path="/items" component={NewItems} />
<Route component={NotFound}/>
</Switch>
</div>
</Grid>
<Footer/>
</div>
);
}
}
const PrivateRoute = ({component: Component, authed, ...rest}) => {
return (
<Route
{...rest}
render={(props) => authed === true
? <Component {...props} />
: <Redirect to={{pathname: '/login', state: {from: props.location}}} />} />
)
}
When user posts credentials (or App main component gets rendered) onAuth method gets invoked and sets (or not) currentUser property of App's state. This property is null (when user is not authenticated) and represents userdetails such like id and username (when user is authenticated). Then, in PrivateRoute based on that property component gets rendered or application redirects user back to the login page. And that doesn't work well. I mean when i'm already authenticated and try to access any of private route, i am redirected to proper component. Problem occurs in 2 situations:
right after logging in - application doesnt redirect me to component
i want to access, insted i stay on the login page.
refreshing page (in browser) corresponded to private route.
It seems like PrivateRoute component doesnt get refreshed when currentUser property gets changed, which is kinda weird because i'm using similar approach in ApplicationHeader to display username when user is authenticated (and that is refreshed correctly).
So, what am i doing wrong here?
I did it rendering the route or the redirect depending on the condition and it worked for me.
Something like the following:
class PrivateRouteComponent extends React.Component{
render(){
return (
this.props.isAuthenticated===true?
(
<Route path={this.props.path} render={this.props.component} />
):
(<Redirect to={{
pathname: '/login',
state: { from: this.props.path }
}} />));
}
}

Why wont my Auth0 find my callback route in react?

Auth0 redirects to http://localhost:3000/callback#/acccess-token=dxy
I'm getting a blank screen in my react app.
Heres my main app.js
render((
<HashRouter>
<Main />
</HashRouter>
), $('#app')[0]);
My main contains my routes.js component.
class Routes extends Component {
constructor(props, context) {
super(props, context);
this.state = { mainData: this.props.mainData };
this.handleAuthentication = this.handleAuthentication.bind(this)
}
componentWillReceiveProps(newProps) {
this.setState((previousState) => update(previousState, {
mainData: { $set: newProps.mainData },
}));
}
handleAuthentication(nextState, replace) {
if (/access_token|id_token|error/.test(nextState.location.hash)) {
this.props.auth.handleAuthentication();
}
}
render() {
return (
<div>
<Switch>
<Route path='/callback' render={props => {
this.handleAuthentication(props);
return <Callback {...props} />
}} />
<Route exact path='/' render={props => (
<Dashboard changeAppBar={this.props.changeAppBar} userProfile={this.state.mainData.userProfile} windowHeight={this.props.wh} windowWidth={this.props.ww} />)}
/>
<Route path='/settings' render={props => (
<Settings changeAppBar={this.props.changeAppBar} userProfile={this.state.mainData.userProfile} />)}
/>
</Switch>
</div>
);
}
}
export default Routes;
Heres my init of auth0
this.auth0 = new auth0.WebAuth({
clientID: 'oiEjW4Mf6Ju4BvRfHeuObQnMbghKs38g',
domain: 'cryptok1ng.auth0.com',
responseType: 'token id_token',
redirectUri: 'http://localhost:3000/callback'
})
Everything works fine until I get redirected from auth0 back to /callback. Simply doesn't find a screen /route and renders nothing.
Screenshot of the console. /callback breakpoint is never hit.
Thanks for any help I've been going through the docs and answers to no avail.
I am assuming you In Auth0 front end client configuration> you have added the callback URi as http://localhost:3000/callback and saved it.
And also in your callback.html file you added some tags to show up something once the token is authenticated properly.
If everything is fine and you still get blank error. Please post your console screenshot to have a look.

Categories