Modify the background of the parent component when hovering in ReactJS

Here is my React code snippet that I am working with:

Code

My goal is to change the background of the App component to the "E-commerce" picture when hovering over it.

This should apply to all other pictures as well.

Any assistance in solving this issue would be greatly appreciated.

Answer №1

According to the React documentation, it is advised to use context only for global state such as the current user or theme. Utilizing context for components can reduce their reusability.

For reference: updated code

The component tree structure is as follows: App -> SolutionBox -> SolutionItem.

When you need to "react" to an event in SolutionItem from App but SolutionBox is in between, you will have to pass the event through SolutionBox to reach App.

Step 1

Add a prop to SolutionItem named onHover, which will be a callback function allowing any parent component to respond to changes.

function SolutionsSectionBoxItem({ solutionIMG, onHover }) {
  let callOnHover = state => {
    if (_.isFunction(onHover)) {
      onHover(state);
    }
  };

  return (
    <div className="solutions-section-item-box">
      <img
        src={solutionIMG}
        alt=""
        onMouseEnter={() => {
          callOnHover(true);
        }}
        onMouseLeave={() => {
          callOnHover(false);
        }}
        className="solutions-section-item-img"
      />
    </div>
  );
}

Step 2

Introduce a prop to SolutionBoxItem called onBGChanged, which again will be a callback function triggered upon any SolutionItem hover event. This function will accept a menuName string and pass the current or default menu name.

function SolutionsSectionBox({ onBGChanged }) {
  let callBGChanged = menuName => {
    if (_.isFunction(onBGChanged)) {
      onBGChanged(menuName);
    }
  };

  return (
    <div className="solutions-section-box-box">
      <SolutionItem
        solutionIMG={Ecommerce}
        onHover={state => {
          callBGChanged(state === true ? "Ecommerce" : "default");
        }}
      />
      <SolutionItem
        solutionIMG={SalesMarketing}
        onHover={state => {
          callBGChanged(state === true ? "SalesMarketing" : "default");
        }}
      />
      <SolutionItem
        solutionIMG={Analytics}
        onHover={state => {
          callBGChanged(state === true ? "Analytics" : "default");
        }}
      />
      <SolutionItem
        solutionIMG={Middleware}
        onHover={state => {
          callBGChanged(state === true ? "Middleware" : "default");
        }}
      />
    </div>
  );
}

Step 3

In the App component, listen for changes. Here, update the state whenever the mouse enters or leaves a solution item. To change the background, CSS is used to control the background URL. This might be challenging as different CSS classes would be required for each background type based on the bgImage state value.

    export default function App() {
  const [bgImage, setbgImage] = useState(E);

  const onBGChanged = menuName => {
    setbgImage(menuName);
  };

  return (
    <div className={`App ${bgImage === "default" ? "" : `App${bgImage}`}`}>
      <SolutionBox onBGChanged={onBGChanged} />
    </div>
  );
}

In CSS

Maintain the original App class and add an additional one based on the bgImage value, like 'AppEcommerce', 'AppSalesMarketing', etc., to update the background-image accordingly.

.AppEcommerce {
  background-image: url(https://placekitten.com/600/600);
}

.AppSalesMarketing {
  background-image: url(https://placekitten.com/500/800);
}

.AppAnalytics {
  background-image: url(https://placekitten.com/800/500);
}

.AppMiddleware {
  background-image: url(https://placekitten.com/700/700);
}

Extra

To ensure the incoming props are functions before calling them, lodash is added as a defensive measure. This practice is recommended for future-proofing the component.

let callBGChanged = menuName => {
    if (_.isFunction(onBGChanged)) {
      onBGChanged(menuName);
    }
  };  

Answer №2

There are two approaches to resolving this issue. One involves passing down a function to update state, while the other utilizes useContext. In this scenario, using context is more appropriate because you are passing down a function across multiple components that do not need to be aware of it.

The first step is to make the background image dynamic in the styling of the div and leverage context:

// Define the context outside the component
export const BackgroundContext = React.createContext(null);

// -- code snippet
const [backgroundImage, setBackgroundImage] = useState(Ecommerce);
const updateBackgroundImage = newImage => setBackgroundImage(newImage);

// -- code snippet
<BackgroundContext.Provider value={updateBackgroundImage}>
  <div className="App" style={{ backgroundImage: `url(${backgroundImage})` }}>
  {/* -- code snippet */}
</BackgroundContext.Provider>

Now in your SolutionsSectionBoxItem component, you can import the background context:

import BackgroundContext from "../App";

Then, utilizing the context and React's mouseover API, you can update the selected background image:

  const setBackgroundImage = useContext(BackgroundContext);
  // -- snippet
  <img onMouseOver={() => setBackgroundImage(solutionIMG)} {/* -- snippet -- */} />

For further information, you can refer to: https://reactjs.org/docs/hooks-faq.html#how-to-avoid-passing-callbacks-down

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

The resize function fails to trigger when it is required

Struggling to get this code working properly. If the window width is greater than 800, I want 6 images with a red background. If the window width is less than 800, I want 4 images with a blue background. I need this functionality to work both on r ...

Activating Vue-Bootstrap components through an image click event in VueJS 2

Seeking to achieve: VueJS integration with Bootstrap for clickable cards I am currently working on a VueJS project where I want the cards to be clickable and reveal collapsible elements upon click. To accomplish this, I have implemented a button with the ...

Amusing antics observed when hovering over a div in Firefox

Issue resolved, many thanks to all Here is the dilemma I am dealing with something like this <a href='http://google.com' class="buy_now" > <div class='yada yada' > Go </div> </a> buy_now changes backgro ...

Using gradient colors for the background on the ::selection pseudo-element

Can you apply a gradient color to CSS ::selection? I tried using the following code: ::selection { background-image: -webkit-linear-gradient(left, #ee4037 0%, #eb297b 100%); } However, it did not have the desired effect. ...

Tips for incorporating transition animations into route changes in next.js

On the homepage, there are 2 links that I want to have distinct transition animations for. For example, if I click the link on the left, the animation should start from the left and move towards the right when changing routes. ...

Is it possible to override Material UI styles with css/scss?

Currently, I am using SCSS because it integrates well with NextJS. I find the SCSS module system easy to work with and would like to continue using it with Material-UI. However, Material-UI uses JSS which involves a lot of boilerplate code. I prefer not to ...

Developing Reactive Selections with Material-UI is made easy

After spending about 5 hours on a task that I thought would only take 15 minutes, I still can't figure out the solution. The issue is with my React App where I have two dropdowns in the Diagnosis Component for users to select Make and Model of their a ...

The appearance of the website varies across different web browsers

My current project involves creating a portfolio showcasing my work, but I've encountered an issue: When you visit my website and click on the "About" link, the text at the bottom of the tab is displayed differently in Chrome compared to IE and Firef ...

Text wrapped automatically to display multiple lines with spacing between each highlighted line

Question about CSS formatting and spacing. I need to automatically break sentences into new lines based on the width of the container. For example, a sentence like: This is a sentence should be displayed as: This is<br>a sentence I am trying ...

Utilize the id in AngularJS to bring attention to a specific row within a table

I am brand new to using angularjs. I currently have a table structured like this: HTML <table class="table table-striped" id="manageResumeTable"> <thead class="text-center text-info text-capitalize"> <th class="text-center col- ...

The appearance of HTML in JSP and CSS output in a Spring application is different from the local environment

For my web application's landing page, I created the design using HTML and CSS. Typically, I first design it on scratchpad.io before implementing it into my STS IDE. However, when I run the application, the output of the page appears different from th ...

Is there a way to achieve a straightforward three-column stacked layout in Bootstrap 5 that spans 100% of the viewport height?

Today I decided to try out Bootstrap 5 for the first time. However, I am facing a challenge in creating a 3 stacked column layout with box-1, box-2, and box-3 on top of each other, taking up 100vh. I have shared a redacted version of the code below, wher ...

Parenting and Child Components: Keeping the State in Sync

I am currently diving into my initial React project which focuses on a basic expense tracker for credit cards. While I'm still in the learning phase, I hope you can decipher the intent behind my code. My current roadblock involves mapping the state an ...

What are the steps to modify the text color in WKWebView?

I've customized my ViewController to include a WKWebView, where I load my content from both .html and .css files. The result resembles a controller for reading books within the Apple Books app. do { guard let filePath = Bundle.main.path(fo ...

When working with Web Workers in Jest, you may encounter an error stating "Cannot use 'import.meta' outside a module."

I'm currently developing a web application using nextjs 10.1.3. To improve performance, we have integrated a web worker on one of the pages and intend to add more workers in the future. All our code is thoroughly unit tested, and with the use of the w ...

reactjs error: Attempting to utilize the toLowerCase method on an undefined property during double mapping

My issue involves a JSON structure that requires mapping a function twice in a loop to access objects within an array. Once mapped, I need a textbox for searching the data list. However, I am encountering the following error: TypeError: Cannot read proper ...

ReactJS requires HTTP server to transpile babel code before running

I am a beginner when it comes to working with reactjs and I am currently in the process of setting up babel to execute babel code without having to serve HTTP files. Following the instructions on the Package Manager, I have successfully installed it along ...

How do you determine the dimensions of a background image?

My div is a perfect square, measuring 200 pixels by 200 pixels. The background image I've chosen to use is larger at 500 pixels by 500 pixels. I'm searching for a method to ensure that the entire background image fits neatly within the confines ...

Modifying property values using the onError event when encountering an error with the MUI DateTimePicker and

My goal is to set the 'myError' variable to true when MUI DateTimePicker throws an onError event, but for some reason it's not working. The code itself seems correct because if I replace () => {setValue({ ...value, ...

Tips for setting background colors as a prop for Material UI cards in React JS

Currently utilizing the Material UI next framework to construct a wrapper for the card component. This customized wrapper allows for personalization of the component. I have successfully extended the component so that the title and image within the card ca ...