9

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.

3
  • 1
    First of all as checkSession is component function , u need to use this.checkSession(); to call it. For checking whether the user sesssion is valid or not. You make the api call in lefecycle methods. I cannot tell you correct lifecycle before i know what version of reactjs you are using. Please tell that Commented Aug 8, 2018 at 8:26
  • Thanks for the reply. I am using the latest version of React. Commented Aug 8, 2018 at 8:31
  • 1
    Side note: Your fetch call is missing a check for success, details in this post on my anemic little blog. Commented Aug 8, 2018 at 8:41

4 Answers 4

18

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(() => {
        //this runs before render

    }, []);
}

Read More: https://reactjs.org/docs/hooks-reference.html#uselayouteffect

Sign up to request clarification or add additional context in comments.

4 Comments

"Prefer the standard useEffect when possible to avoid blocking visual updates."
I agree @KostasMinaidis
how can this be the right answer. The question was about a react class component
uselayouteffect does NOT fires before render, it fires before React repaints the screen. render !== mount. Check my answer.
8

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.

5 Comments

Thank you for this. I'll take a look at componentDidUpdate and hopefully get this working.
I'm still struggling with how to execute the function before render() is hit. I thought about putting the code inside componentDidMount instead, but the login form shows before the session is checked and then is removed. I assume this is because the code is rendered before componentDidMount is called. Do you know where I might put this? Would I possibly need to set the state to show a blank page and then have componentDidMount set the correct states (does that make sense?). Thanks if you can help.
@Matt - You can't wait for an asynchronous process to complete before render is called. Instead, you do one of two things: 1. Have the component handle rendering itself correctly before the process is complete, with appropriate state for the fact it doesn't know the result yet (and then of course, it will re-render when its state changes because the process completes). 2. Have the parent component do the asynchronous check, and then only render this component when the check is complete.
I think that makes sense now, I'll have to handle it with componentDidMount to re-render the correct data. It may actually be easier to add the function to index.js and then render <App /> after the checks. Am I on the right tracks? Thank you.
@Matt - Yes (sorry, I pointed you at the wrong method originally but you're right it's componentDidUpdate, have updated the answer now). Either of those (using componentDidUpdate or waiting until you have the session before having your app render the component) is good. Probably the latter unless your component can do something useful while the check is outstanding.
4

useLayoutEffect is NOT correct way to execute code before render. Quote from react.dev

useLayoutEffect is a version of useEffect that fires before the browser repaints the screen.

repaints does not mean that it'll trigger before the first render.

In Class components, componentWillMount will be executed before the render. The complete match of componentWillMount is not completely exist in functional components.

Possible solution is, put a boolean flag, make it true in useEffect (with empty dependency array), if it's false, that means it's before render.

export default function App() {
  const isMounted = useRef(false)

  if (!isMounted.current){
   // your code here, executes before render
   }

  useEffect(() =>{
  // Initial render has been completed
  // make the flag true
    isMounted.current = true
  },[])

  return (
    <div className="App">
      
    </div>
  );
}

This way, you won't re-render the component (since no setState() triggers exist).

1 Comment

This approach looks promising. Thanks!
1
export default function App() {
  const initialRenderRef = useRef(true);

  if (initialRenderRef.current){
    initialRenderRef.current = false;
    // your code here, executes before render
  }

  return (
    <div className="App">
      My super app!
    </div>
  );
}

Your code will run once, at first render. initialRenderRef prevent code to run twice or more.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.