Having trouble applying styles to a component using forwardRef

I'm relatively new to React and still trying to wrap my head around the component's lifecycle. However, the issue at hand is proving to be quite perplexing.

One thing that confuses me is why adding "setState(10);" causes the style of the "Test" component to revert back to its default value, while the

<div ref={ref2}>Hi</div>
keeps its style unchanged (see image below).

I understand that calling "setState(10);" triggers a re-render, but what I can't comprehend is why the style of the "Test" component resets to its default state.

Additionally, please disregard the "practical use" of using setState(10) - I know it serves no purpose as it's never utilized. I also understand that including "state" as a useEffect dependency can resolve this issue. However, my main concern is understanding the reason behind the component's style reverting to its default values.

import React, { useEffect, useState, useRef } from "react";

export default function App() {
  const [state, setState] = useState();
  let ref1 = useRef();
  let ref2 = useRef();
  useEffect(() => {
    console.log("useEffect called ", ref1.current);
    ref1.current.style.backgroundColor = "red";
    ref2.current.style.backgroundColor = "green";
    setState(10);
   // }, [state]);
  }, []);

  const Test = React.forwardRef((props, ref1) => {
    console.log("test called - rendering webpage", ref1.current);
    return (
      <div ref={ref1} {...props}>
        HI from Test{" "}
      </div>
    );
  });

  return (
    <div className="App">
      <Test ref={ref1} />
      <div ref={ref2}>Hi</div>
    </div>
  );
}

Console output

test called - rendering webpage undefined
useEffect called <div style="background-color: red;">HI </div>
test called - rendering webpage <div style="background-color: red;">HI </div>

https://i.sstatic.net/MP372.png

Answer №1

The disappearance of the style is due to your Test component being defined inside your App component. This means that every time App renders, a new component type named Test is created. Although the content of the component remains the same, react recognizes it as a new type and replaces the old one. Consequently, any changes made to the previous component are lost.

To resolve this issue, you should move Test outside of App. By doing so, the component is defined only once and will not be remounted with each render.

export default App() {
  // ...
}

const Test = React.forwardRef((props, ref1) => {
  // ...
})

This adjustment should prevent the reset and allow you to use refs effectively, although I advise against using refs for styling. While refs can be necessary at times, the recommended approach for styling a component is through the style prop. If styling needs to be changed dynamically, utilize a state variable to control the style prop instead.

If you directly manipulate the style with javascript like

ref1.current.style.backgroundColor
, react cannot register these changes. As a result, react may override or skip updating styles that were modified manually.

export default function App () {
   const [colored, setColored] = useState(false);
   useEffect(() => {
     setColored(true);
   }, [])

   return (
    <div className="App">
      <Test style={colored ? { backgroundColor: "green" } : undefined} />
      <div style={colored ? { backgroundColor: "red" } : undefined}>Hi</div>
    </div>
  );
}

// Not essential anymore, but left for completeness
const Test = React.forwardRef((props, ref) => {
  return (
    <div ref={ref} {...props}>
      HI from Test
    </div>
  );
});

Answer №2

import React, { useEffect, useState, useRef } from "react";

export default function App() {
  const [state, setState] = useState();
  let ref1 = useRef();
  let ref2 = useRef();
  useEffect(() => {
    console.log("useEffect called ", ref1.current);
    ref1.current.style.backgroundColor = "red";
    ref2.current.style.backgroundColor = "green";
    setState(10);
    // }, [ref.current]);
  }, [state]);

  const NewComponent = React.forwardRef((props, ref1) => {
    console.log("NewComponent called - rendering webpage", ref1.current);
    return (
      <div ref={ref1} {...props}>
        Greetings from NewComponent{" "}
      </div>
    );
  });

  return (
    <div className="App">
      <NewComponent ref={ref1} />
      <div ref={ref2}>Hello</div>
    </div>
  );
}

This issue occurs because when the state is updated, the entire component is re-rendered. The useEffect hook only runs once on componentDidMount, so the new reference you get is not updated. To fix this, you should use the state as a dependency of the useEffect.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Updating a div's border using JavaScript

I recently generated a div element dynamically through code. var Element; Element = document.createElement('div'); My goal now is to modify the right and bottom borders to "#CCCCCC 1px solid". I aim to achieve this without relying on any exte ...

It appears that protractor-flake is programmed to re-run all tests instead of just the ones that have failed

Running tests using the latest version of "[email protected]", encountering failures during testing but the tests are rerunning again. No custom reporter used except Allure reporting. Below is the command used for running: protractor-flake --max-at ...

Group Hover by StyleX

I recently experimented with the innovative StyleX library and encountered a particular challenge. Can a group hover effect be achieved for a component solely using this library? For instance, let's assume we have the following component in Tailwind ...

Library of User Interface components for React Native applications

As I embark on my journey of building my first major app using React Native, a question comes to mind. Is there a UI framework available for React Native that offers pre-styled components right out of the box? Similar to how Ionic provides a base theme a ...

extract the content of CSS pseudo-elements using Python or Selenium

Currently, I am working on automating a web service using Selenium and Python. My ultimate goal is to extract the text "test" located below. However, I am facing some challenges in figuring out if this is feasible through Selenium or any Python library. & ...

JavaScript - Verify if all properties belonging to an object are set to true

I'm facing a challenge with an object that contains various fields which could potentially be set to true for a user, similar to a list of achievements. If I have an object like {one: true, two: false, three: true}, how can I prevent the function from ...

Error message: "Unassigned value in knockout.js"

Here is my code snippet for binding to a textbox: var CategoryViewModel = { categoryModel: ko.observable({ categoryId: ko.observable(), categoryName: ko.observable(), active: ko.observable() }), GetCategoryById: functio ...

Creating a visually striking layout with Bootstrap card columns masonry effect by seamlessly adjusting card heights to prevent any

When using the bootstrap card columns masonry and a user clicks on a button inside a card, the height of the card changes dynamically by adding a card-footer. However, in certain situations, the cards change position causing a jumpy effect. To see this i ...

Encountering an issue when trying to set the "files" property in the Eslint Config while using the Eslint VSCode Extension

When attempting to include the "files" property in the ESLint configuration file ".eslintrc.cjs", I encountered an error from the EsLint VsCode Extension: ESLint: ESLint configuration in client.eslintrc.cjs is invalid: - Unexpected top-level property "fi ...

Utilizing AXIOS and .NET 5 Web API for Managing Access and Refresh Tokens

In my React application using Redux, we are utilizing Axios to interact with our Web API. To ensure security, we have implemented JWT access tokens along with refresh tokens. The server side token generation for our Web API is based on this code: https:/ ...

The issue of PHP timing out occurring within a public function

After pulling a "large" SQL query from the database with 50,000 records and completing it in about 5 seconds, I run it through a function to create an HTML table. However, the process keeps timing out for some reason. If I limit the query to less than 30k ...

After ReactDOM is used, the JavaScript code is no longer functioning properly

While working on my latest project, I utilized react.js and encountered an issue where javascript seemed to stop working when using ReactDOM to render a class extended from React.Component. I noticed that the alert() method would not work if it was placed ...

Achieving equal height for two divs and centering them

Is it possible to align the height of two floated divs so that the second div slips down, and the container width automatically adjusts to fit the child width while centering the divs? I apologize for any language errors. :( <!DOCTYPE html PUBLIC "-//W ...

We encountered an error: The module 'history' cannot be located in the specified directory: '/Users/aronfischer/the_odin_project/passport-starter/src'

I keep encountering this issue: Module not found: Can't resolve 'history' in '/Users/aronfischer/the_odin_project/passport-starter/src' whenever I run npm start and I'm struggling to identify the cause. I believe my file str ...

Is there a way to retrieve the list of files from a static public folder using javascript?

I have successfully set up a public folder directory using express and node. For instance, this code works perfectly - var testImage = new Image(); testImage.src = '/images/png/avatar.png'; However, I need to access several images stored ins ...

Ways to achieve 8 columns in a single row using Javascript and Bootstrap

Recently, I created a simple function for searching movies and manipulating them in the DOM. The issue arises when a movie name is entered and the API response returns around 20-30 recommendations. I wanted to display this fetched data in 8 columns per row ...

What is the method to remove the overlay from view?

Can anyone help with a small issue I'm having? When I click on button one, a modal popup appears but the overlay doesn't disappear when unloading. I've tried the code below, but can someone suggest what might be causing the problem? var po ...

Encountered an error when attempting to access the property "addOption" on an undefined object

Every time I try to implement search functionality, I keep running into this error: "cannot read property 'addOption' of undefined in JavaScript selectize." I have confirmed that my result array does contain data. This is my JavaScript code: ...

Tired of searching for a way to activate the Inspect function in the right-click menu on a custom dialog while debugging Google apps

I'm currently working on implementing a file picker function within Google Sheets by using the Google Picker API. Although I have managed to display a customized dialog window for selecting files from my Google Drive, the output is not exactly what I ...

Upon sending an HTTP POST request from JavaScript to a Node server, the body was found to be

Trying to make an XMLHttpRequest from JavaScript to my node server. This is the request I am sending: var data = { "fname": "Fasal", "lname": "Rahman" }; var body = JSON.stringify(data); var xhttp = new XMLHttpRequest(); xhttp.open("POST", "/admin"); xhtt ...