Matt
Matt

Reputation: 551

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.

Upvotes: 9

Views: 73061

Answers (4)

Anil Singh
Anil Singh

Reputation: 4501

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

Upvotes: 18

Super Hero
Super Hero

Reputation: 11

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.

Upvotes: 0

GLHF
GLHF

Reputation: 4035

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).

Upvotes: 3

T.J. Crowder
T.J. Crowder

Reputation: 1074208

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.

Upvotes: 8

Related Questions