Set state from App.js component in login.js Component in ReactJS - javascript

Well, I am trying to set the state of my App.js Component in the login.js component to true. The code I have in my App.js is this:
state = {
isAuth: false
};
And this is how I try to set the isAuth to false in my login.js Component:
statusCode:{
200: function(){
this.App.state.isAuth = true;
console.log('it's working!')
}
}
This is how I import the App Component:
import App from './App';
If the user successfully login the status code should be 200 and after receiving this status code the isAuth of the App.js component should be set to true. Don't know why this is not working. I'm getting the error TypeError: Cannot read property 'state' of undefined.

It's not possible to setState directly from another component. So, one solution is to pass a function that handles the setState to the other component. For example, in your case:
App.js
import Login from "path/to/Login"
class App extends Component {
state = {
isAuth: false
}
handleIsAuthChange = (isAuth) => {
this.setState({ isAuth })
}
render () {
return <Login handleIsAuthChange={this.handleIsAuthChange} />
}
}
Then you can access the function by props
Login.js
class Login extends Component {
setIsAuth = (isAuth) => {
this.props.handleIsAuthChange(isAuth)
}
// Your Code...
}
Another possible solution is to use the Context API, but this is certainly the easiest way to do it.
If you're still a little lost on this, I recommend you to take a look at this answer as well https://stackoverflow.com/a/55028734/11194008

Related

How to implement routing from and to root (index.js) in react with redux

I'm programming a react server webpage, trying to redirect from index.js (i.e: localhost:3000) to Login page: (localhost:3000/login), and from login to index (in case of failed login). What do I need to write in index.js and login.js?
This is for a react based app, using also redux framework. I've tried a few ways including setting up a BrowserRouter etc. All won't really do the redirecting.
My current code is this:
in index.js:
class Index extends Component {
static getInitialProps({store, isServer, pathname, query}) {
}
render() {
console.log(this.props);
//const hist = createMemoryHistory();
if (!this.props.isLoggedIn){
return(<Switch><Route exact path = "/login"/></Switch>)
}
else{...}
in login.js:
render() {
console.log(this.props);
if (fire.auth().currentUser != null) {
var db = fire.firestore();
db.collection("users").doc(fire.auth().currentUser.uid).get().then((doc) => {
this.props.dispatch({ type: 'LOGIN', user: doc.data() });
})
}
const { isLoggedIn } = this.props
console.log(isLoggedIn)
if (isLoggedIn) return <Redirect to='/' />
I except the root to redirect to login if no session is on, and login to redirect to root once there is a successful login.
I am currently getting "You should not use <Switch> outside a <Router>" at index (I have tried to wrap with BrowserRouter, ServerRouter, Router. the first says it needs DOM history. adding history does not change error. two others do not error but are blank display on browser.)
and "ReferenceError: Redirect is not defined" at login.
Any help will be appreciated.
you can use a HOC (Higher-Order Components)
something like this
export default ChildComponent => {
class ComposedComponent extends Component {
componentWillMount() {
this.shouldNavigateAway();
}
componentWillUpdate() {
this.shouldNavigateAway();
}
shouldNavigateAway() {
if (!this.props.authenticated) {
this.props.history.push('/')
}
}
render() {
return <ChildComponent {...this.props} />
}
}
}
As of now you're trying to return a route declaration wrapped in a Switch component. If you want to redirect the user to the /login page if hes not logged in, you need the route to be declared higher up in the component hierarchy, and then you would be able to return the <Redirect /> component. Either way, I would suggest you check out the react router documentation to see how they do authentication.
https://reacttraining.com/react-router/web/example/auth-workflow

How to print another component when i logout. React and Firebase

How I can render another component when i logout on firebase.
I´m trying to re-render the page to print the LoginPage
This is my LoginPage that is render when I loggin with another form.
import React, { Component } from "react";
/*Importing firebase*/
import firebase from "firebase";
/*Importing pages*/
import LoginPage from "../login/LoginPage";
/*Importing components*/
import Header from "./containers/HandleHeader";
class IndexPage extends Component {
shouldComponentUpdate() {
firebase.auth().onAuthStateChanged(user => {
if (user) {
} else {
this.forceUpdate();
return <LoginPage />;
}
});
}
render() {
return (
<div>
<Header />
</div>
);
}
}
export default IndexPage;
And this is my handleLogout that work when I click my logout button.
handleLogout = e => {
firebase
.auth()
.signOut()
.then(() => this.forceUpdate());
};
I want to make that when I logout I don´t need reload the page.
Usually the best way to do this is to maintain the logged-in state somewhere, then protect the entry points to any components that require authentication with logic like this:
render() {
const { loggedIn } = this.props;
if (!loggedIn) return <Redirect to="/login" />;
// Reset of component rendered below this point
}
Note that this logic can be in the component itself, some parent component, or some higher order component. The key is to have it somewhere that will prevent access to any protected component by redirecting in the render method before any protected information can be reached.
Redirecting is often achieved using some routing package like, say, react-router-dom, to navigate around. This means that when you log out, a user is implicitly always redirected because they can no longer access the protected components anymore.

Need to Execute Function before render() in ReactJS

I've created a login system with React which stores a session when the user logs in. When the page is reloaded, I have added a function which should check if the session exists and then either setState() to true or to false.
As I'm new to React, I'm not sure how to execute this function. Please see my code below for App.js:
import React from 'react';
import './css/App.css';
import LoginForm from "./LoginForm";
import Dashboard from "./Dashboard";
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
renderLoginForm: true
};
this.handleLoginFormMount = this.handleLoginFormMount.bind(this);
}
handleLoginFormMount() {
this.setState({
renderLoginForm: false
});
}
// Check session function.
checkSession() {
fetch('/check-session', {
credentials: 'include'
})
.then((response) => {
return response.json();
})
.then((sessionResult) => {
if (sessionResult.username) {
console.log('false');
this.setState({
renderLoginForm: false
});
} else {
console.log('true');
this.setState({
renderLoginForm: true
});
}
})
.catch((error) => {
console.log('Error: ', error);
});
}
render() {
checkSession();
return (
<div className="App">
{this.state.renderLoginForm ? <LoginForm mountLoginForm={this.handleLoginFormMount} /> : null}
{this.state.renderLoginForm ? null : <Dashboard />}
</div>
);
}
}
export default App;
Having checkSession() in this position outputs the following in the console when loading the page:
Line 50: 'checkSession' is not defined no-undef
If I put the function outside of the class App extends React.Component {}, then it tells me that I cannot set the state of undefined.
Functional Component: In my case I wanted my code to run before component renders on the screen. useLayoutEffect is a hook provided by React for this exact purpose.
import React, { useLayoutEffect } from "react";
...
const App = () => {
useLayoutEffect(() => {
//check local token or something
}, []);
}
Read More: https://reactjs.org/docs/hooks-reference.html#uselayouteffect
Having checkSession() in this position outputs the following in the console when loading the page:
Line 50: 'checkSession' is not defined no-undef
That's because it's a method, but you're calling it like a freestanding function. The call should be this.checkSession();. But keep reading.
Separately:
The render function must be pure, it cannot have side-effects like changing state. Instead, put any side-effects code in componentDidMount; from the documentation for that lifecycle method:
If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
Be sure that your component renders correctly for the original state (before the session check), as well as for the updated state (after the session check).
More about lifecycle methods and such in the documentation.
Alternately, if this component can't do anything useful without the session, you might move the session check to its parent component, and have the parent only render this child component when it has the session check results.

Unable to use setState in react component

I have the following code that is not letting me set the state ever after getting mounted.
Here is the code
import React, { Component } from 'react';
import Messages from '../locale/en/Messages';
import '../styles/base.css';
class AlertService extends Component {
state = {
message: '',
classType: 'alert-info',
isMessageSet: false
}
Messages = new Messages();
componentDidMount = () => {
console.log('This has mounted'); // This is working
}
componentWillUnmount = () => {
console.log('Is this getting unounted ?'); // This is working, the component is not getting unmounted
}
setAlert = (key, type, isMessage, readMore) => {
let message = isMessage ? key : this.Messages[key];
let classType = 'alert-info';
if (type === 0) {
classType = 'alert-danger';
} else if (type === 1) {
classType = 'alert-success';
}
this.openMessage(message,classType);
}
openMessage = (message,classType) =>{
this.setState({
message: message,
classType: classType,
isMessageSet: true
});
}
closeMessage = () => {
this.setState({
message: '',
classType: 'info',
isMessageSet: false
});
}
render() {
let classes = this.state.classType + ' ' + 'alertBox';
return (this.state.isMessageSet ?
<div className={classes}>
<div className="col-md-11"> {this.state.message} </div>
<div className="col-md-1 closeAlert" onClick={this.closeMessage}> x </div>
</div>
: null
)
}
}
export default AlertService;
I am geting the following error when trying to call the function setAlert from outside this component.
However if I set the isMessageSet property to true then on clicking the X and calling the closeAlert method, it works fine.
componentDidMount indicates that the component is getting mounted and componentWillUnmount is never getting executed , I am not sure what is wrong here
Error Message
Can't call setState on a component that is not yet mounted. This is a no-op, but it might indicate a bug in your application. Instead, assign to this.state directly or define a state = {}; class property with the desired state in the AlertService component.
setState should not be called from outside the component. If you want to change the state from outside, use props.
And as the error message says, the component is not mounted. You could mount it by adding <AlertService /> to the Layout.
As you have mentioned in one of the comments that you are trying to call the setAlert function after instantiating the AlertService class, I suggest you to please take a look as to how you are doing that. The right way is:
this.AlertService = React.render(React.createElement(AlertService), mountnode) //mounts the component
this.AlertService.setAlert() // now you can call the function
Depending upon your usecase you can do like above.
The thing with react is that the child component's methods cannot be called by the parent component. Since those are meant to be private to the child and should therefore be handled by itself. As a hack though we can make use of refs to call the child component's methods but that is not a recommended usecase for refs. Thid can result in bugs in you application.
The best way to achieve the prupose as #vijayst suggested is to change state of your parent component on an alert(whenever message is received) and pass it as a prop to the child. Now update the state for the child under componentWillReceiveProps().
If I understand you correctly you said you tried calling setAlert from another component, it doesn't work but when you called closeMessage it works as expected, but then I noticed you called closeMessage in this same component which would work as expected, if you want to call a function that belongs to this component in another component then you need to import the component into this component then pass the function to it so you would be able to call the function in the component. For example:
import AnotherComponent from '../AnotherComponenet'
<AnotherComponent setAlert={this.setAlert} />

Call component function from a JS File

I want to know If I can do this in react, I want to call a function or method of a react component from a JS file, so I could change the state of that component.
I have these three files for example
First App.js
import React,{Component} from 'react';
import Login from './Login';
class App extends Component{
constructor(){
super();
this.state = {session:false}
}
changeStateSession(state_session){
this.setState({session:state_session});
}
render(){
return(
this.state.session
?<div>Content</div>
:<Login/>
);
}
}
Login.js
import React, {Component} from 'react';
import Auth from './Auth.js';
class Login extends Component{
constructor(){
super();
}
login(){
Auth.login();
}
render(){
return(
<button onClick={(e)=>login(e)}></button>
);
}
}
And Auth.js
import App from './../../App.js';
const Auth = {
login:App.changeStateSession(true)
};
export default Auth;
What I really want to know is if theres a way that I could call the App function (changeStateSession) from the Auth.js file, the Auth.js file is just an example of what I would like to achieve I know this file doesn't work, but I would like to know If there is a way to achieve something like this in react, hope you can help me , thanks.
The more common way of doing something like this would be to pass your changeSessionState function as a prop to the Login component.
App.js:
class App extends Component {
constructor(props) {
super(props);
this.state = { session: false }
this.changeStateSession = this.changeStateSession.bind(this);
}
changeStateSession(stateSession){
this.setState({ session: stateSession });
}
render(){
return (
this.state.session
? <div>Content</div>
: <Login onSuccess={() => this.changeStateSession(true)} />
);
}
}
Login.js:
class Login extends Component {
constructor(props) {
super(props);
}
login(){
// If your login process is asynchronous
// and returns a Promise, for example
Auth.login()
.then(this.props.onSuccess);
}
render() {
return (
<button onClick={(e)=> this.login(e)}></button>
);
}
}
Now, when this.props.onSuccess is called once your login succeeds, your App component's state will be updated since your changeStateSession method was passed as a prop to your Login component.
The big takeaway here is that if you want to update a parent's state from a child component, passing functions from your parent component to the child component is the way to typically handle it. No other way of updating parent state from a child is recommended.
Also, if there is an absolute necessity to call the changeStateSession function from your Auth.js file, then it's a very similar concept. Just pass the function through and call it there instead.
You should probably use props. Either calling passing the function to a child component or just passing the value to the App component as a prop and calling the function in the parent component

Categories

Resources