By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
rocoderesrocoderes
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Notification Show More
Latest News
How to set the dropdown value by clicking on a table row
Javascript – How to set the dropdown value by clicking on a table row
JavaScript
Attempting to increase the counter, when the object's tag exist
Javascript – Attempting to increase the counter, when the object’s tag exist
JavaScript
Cycle2 JS center active slide
Javascript – Cycle2 JS center active slide
JavaScript
Can import all THREE.js post processing modules as ES6 modules except OutputPass
Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass
JavaScript
How to return closest match for an array in Google Sheets Appscript
Javascript – How to return closest match for an array in Google Sheets Appscript
JavaScript
Aa
Aa
rocoderesrocoderes
Search
  • Home
  • HTML & CSS
    • Login and Registration Form
    • Card Design
    • Loader
  • JavaScript
  • Python
  • Internet
  • Landing Pages
  • Tools
    • Google Drive Direct Download Link Generator
    • Word Count
  • Games
    • House Painter
Follow US
High Quality Design Resources for Free.
rocoderes > JavaScript > Javascript – Class components referencing and setting their own static variables – what is the functional component equivalent?
JavaScript

Javascript – Class components referencing and setting their own static variables – what is the functional component equivalent?

Admin
Last updated: 2024/02/10 at 1:26 PM
Admin
Share
6 Min Read
Class components referencing and setting their own static variables - what is the functional component equivalent?

Problem:

When using class components, I am able to set static variables that will persist on each further instance of the class. This allows me to set a kind of firstRun state on a component, even when calling the same component multiple times.

Contents
Problem:Solution:

I have tried to create this behaviour in a functional component, but when the component is used multiple times, it seems to forget its states, ref, etc each time.

In the code below, I have two components, one functional and one class. Each one of these components is called three times in App. In the class component I am able to directly set ClassComponent.firstRun which I am then able to reference in further inclusions of the same component. In the functional component I have tried the same with useRef, but this only seems to work per instance of the component, and gets forgotten on each new component.

const { useEffect, useRef } = React;

const FunctionalComponent = (props) => {
  const { id } = props;
  const mounted = useRef(false);
  useEffect(() => {
    if (!mounted.current) {
      console.log('Initial functional component load...', id);
      mounted.current = true;
    } else {
      console.log('Functional component has already been initialised.', id)
    }
  }, []); 
  return (
    <div>Hello, functional component!</div>
  );
};

class ClassComponent extends React.Component {
  constructor(props) {
    super(props);
    this.createSomething();
  }
  
  static firstRun = true;
  
  createSomething() {
    if (ClassComponent.firstRun) {
      console.log('Initial class component load...', this.props.id);
      ClassComponent.firstRun = false;
    } else {
      console.log('Class component has already been initialised.', this.props.id);
    }
  }

  render() {
    return (
      <div>Hello, class component!</div>
    );
  }
}

function App() {
  return (
    <div>
      <ClassComponent id="class-component-1" />
      <ClassComponent id="class-component-2" />
      <ClassComponent id="class-component-3" />
      <FunctionalComponent id="functional-component-1" />
      <FunctionalComponent id="functional-component-2" />
      <FunctionalComponent id="functional-component-3" />
    </div>
  )
}

ReactDOM.render(<App />, document.querySelector("#app"));
<div id="app"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>

The class component works good – I get one log for the initial load, then two logs saying it has already intialised – great! The functional component however is logging three initial load messages.

I have tried using useState, but as I understand this only works for re-renders, and not separate occurences of the component. This also seems to be the same situation when using useRef.

I have read about function closures, and tried to crudely implement one with the code below, but this again is just giving me three Initialised... logs:

const checkInitial = () => {
  let initial = true; 
  return {
    get: function() { return initial },  
    set: function(state) { initial = state; }
  };
}
...
const FunctionalComponent = (props) => {
  const { id } = props;
  const mounted = useRef(false);
  useEffect(() => {
    const firstRun = checkInitial();
    if (firstRun.get()) {
      console.log('Initial...', id);
      firstRun.set(true);
    } else {
      console.log('Already run...', id);
    }
  }, []); 
  return (
    <div>Hello, functional component!</div>
  );
};

I believe that setting a context variable may be able to get around this, but I’d rather not use that right now. I’m also aware that I can lift the state up to the parent, but I want to avoid this as it will most likely cause re-renders.

This situation seems to easy to solve with class components, but these are now obsolete. Is there an easy way to do this purely using functional functions/components?

Cheers!

Solution:

Any hook, whether useState or useRef, is per instance of the component.

If you really want a static variable1, just do exactly the same as you did with the class component – store it on the function object itself:

function FunctionComponent({ id }) {
  if (FunctionComponent.firstRun) {
    console.log('Initial function component render...', id);
    FunctionComponent.firstRun = false;
  } else {
    console.log('Function component has already been rendered before.', id);
  }
  return (
    <div>Hello, function component!</div>
  );
}
FunctionComponent.firstRun = true;

It would be more customary though to just declare a variable in the module scope where the function component is defined:

let firstRun = true;
function FunctionComponent({ id }) {
  if (firstRun) {
    console.log('Initial function component render...', id);
    firstRun = false;
  } else {
    console.log('Function component has already been rendered before.', id);
  }
  return (
    <div>Hello, function component!</div>
  );
}

If you don’t want the log to appear every time the component is rendered, but only once, when it is mounted, you can use an effect or the initialiser of a state:

let firstRun = true;
function FunctionComponent({ id }) {
  useEffect(() => {
    if (firstRun) {
      console.log('Initial function component mount...', id);
      firstRun = false;
    } else {
      console.log('Function component has already been mounted elsewhere.', id);
    }
  }, []);
  return (
    <div>Hello, function component!</div>
  );
}
let firstRun = true;
function FunctionComponent({ id }) {
  const [isFirst] = useState(() => {
    if (firstRun) {
      firstRun = false;
      return true;
    } else {
      return false;
    }
  });
  return (
    <div>Hello, {isFirst && 'first'} function component!</div>
  );
}

1: You probably don’t want a static variable. It’s ok for constants, but as soon as you have stateful static variable, it’s essentially global state. Avoid that.

Related

Subscribe to Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

Share this Article
Facebook Twitter Email Print
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article Connect HTMLMediaElement to Android playback controls Javascript – Connect HTMLMediaElement to Android playback controls
Next Article Issue value of checkbox not affect on model property speakstuff when call action? Javascript – Issue value of checkbox not affect on model property speakstuff when call action?
Leave a comment Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

- Advertisement -

You Might Also Like

How to set the dropdown value by clicking on a table row

Javascript – How to set the dropdown value by clicking on a table row

February 11, 2024
Attempting to increase the counter, when the object's tag exist

Javascript – Attempting to increase the counter, when the object’s tag exist

February 11, 2024
Cycle2 JS center active slide

Javascript – Cycle2 JS center active slide

February 10, 2024
Can import all THREE.js post processing modules as ES6 modules except OutputPass

Javascript – Can import all THREE.js post processing modules as ES6 modules except OutputPass

February 10, 2024
rocoderesrocoderes
Follow US

Copyright © 2022 All Right Reserved By Rocoderes

  • Home
  • About us
  • Contact us
  • Disclaimer
Join Us!

Subscribe to our newsletter and never miss our latest news, podcasts etc.

Zero spam, Unsubscribe at any time.
Welcome Back!

Sign in to your account

Lost your password?