Elevate state in React to modify classNames of child elements

I have a structured set of data divided into 6 columns representing each level of the hierarchy. When a user makes selections, their chosen location is highlighted with a dynamic CSS class name and displays the relevant data list. I've managed to implement the highlight movement for each selection but encounter an issue when the user navigates back to the top of the hierarchy; it retains the last highlight state.

For instance, if the hierarchy consists of country, state, city and I pick USA, California, LA. If I choose a different country, then return to USA, California remains highlighted. How can I update the class name across all columns?

I understand there are similar discussions on bubbling up state, but I haven't been able to apply them to my situation as I need to go one child level deeper than usual examples.

Code structure: App.js, LocationList.js, Location.js

LocationList.js

class LocationList extends Component {
    constructor(props){
        super(props);
        this.state = {
            title: props.title,
            clicked: false,
         };
        this.handleClick = this.handleClick.bind(this);
    }

    handleClick(selectedItem) { 
       this.props.onListClick(selectedItem) 
       this.setState({clicked: selectedItem})
    }

    isSelected(location){ //current selected item is highlighted
        if(location.LocationId === this.state.clicked.LocationId){
            return 'highlight'
        }
        else {return 'no_highlight'}
    } 

    return( ..//other info.. 
                 <Location
                    location={location}
                    key={location.LocationId+location.LocationName}
                    tier={this.props.level}
                    handler={this.handleClick}
                    highlightClass={this.isSelected(location)}
                  />

Location.js

class Location extends Component {
    constructor(props) {
        super(props);
        this.state={
            locationsList: props.locationList
        }   
        this.onClick = this.onClick.bind(this);       
    }

    onClick(selectedItem) { 
        this.props.handler(this.props.location);
     };

  render() {
        let location = this.props.location;
        console.log(this.props)     

        return(
            <div 
                id="item"
                style={locationStyle}  
                key={location.LocationId} 
                value={location.Name} 
                level={location.Level}
                onClick={this.onClick}
                className={this.props.highlightClass}
            >
                {location.LocationName} 
            </div> 
        );
    }
  }

App.js - this is where I'm stuck

handleClick(selectedItem) {
// See value user clicked
console.log('Selected location: ', selectedItem) 
}

render() {
      return(
          <div className="row">
          <LocationList key="1" level="1" title="Country" lis={this.state.column Tier1} onListClick={this.handleClick}/>
          <LocationList key="2" level="2" title="State" lis={this.state.column Tier2} onListClick={this.handleClick}/>
          <LocationList key="3" level="3" title="City" lis={this.state.column Tier3} onListClick={this.handleClick}/>
  </div>
 );

}

App.css

.no_highlight {
  background-color: transparent
}
.highlight {
  background-color: #007dc34d
}

Answer №1

To maintain the entire selection in the App state, and then transmit the relevant selection to the corresponding LocationList. Afterwards, incorporate distinct handlers for clicks on the LocationList to reset the state.

class App extends Component {
  constructor(props) {
    super(props);
    this.state = { 
      ...
      selection: {
        country: null,
        state: null,
        city: null
      }
    };

    this.handleClick = this.handleClick.bind(this);
  }

  handleClick(getSelection) {
    return location => {
      const selection = getSelection(location);
      this.setState({
        selection: Object.assign({}, this.state.selection, selection)
      };
    };
  }

  render() {
    return (
      <div>
        ...
        <LocationList title="Country"
                      selection={this.state.selection.country}
                      onClick={this.handleClick(country => ({ country, state: null, city: null }))}
                      // other props
        />
        <LocationList title="State"
                      selection={this.state.selection.state}
                      onClick={this.handleClick(state => ({ state, city: null }))}
                      // other props
        />
        <LocationList title="City"
                      selection={this.state.selection.city}
                      onClick={this.handleClick(city => ({ city }))}
        />
      </div>
    );
  }
}

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 button's corners did not appear rounded after setting the borderRadius to '50%' in iOS

Does the same code round off buttons properly in Android but not in iOS? Is the percentage value not compatible with the iOS platform in React? import { TouchableOpacity, Text } from 'react-native'; export default class App extends React.Compone ...

Create an array of routes specifically for private access using Private Route

In my application, I have defined different routes for admins, employees, and clients. Admins can access routes /x, /y, and /z, employees can access routes /a and /b, and everyone including clients can access 4 other routes. I am trying to implement this l ...

Adjust the value of a cell in the MUI Data Grid in real-time

In the Data Grid, there are 9 columns including "Rate" and "Transfer". There is also a column labeled "Total" which should display the multiplication result of "Rate" and "Transfer", adjusting with any changes made to the "Transfer" cell value. The "Transf ...

Change a nested for-loop into an Observable that has been transformed using RxJS

Currently, the following function is operational, but I consider it a temporary solution as I'm extracting .value from a BehaviorSubject instead of maintaining it as an observable. Existing Code Snippet get ActiveBikeFilters(): any { const upd ...

Delaying the call of a JavaScript function with jQuery

Basic JavaScript Function: $(document).ready(function(){ function sampleFunction() { alert("This is a sample function"); } $("#button").click(function(){ t = setTimeout("sampleFunction()",2000); }); }); HTML ...

Animating the Click Event to Change Grid Layout in React

Can a grid layout change be animated on click in React? For instance, consider the following component: import { Box, Button, styled, useMediaQuery } from "@mui/material"; import Row1 from "./Row1"; import React from "react"; ...

react-leaflet LayerSelection creates redundant entries in table

Here is the React version I am using: 16.0.0 And for react-leaflet: 1.6.6 I recently attempted to implement a layer controller on my map which consists of two layers, each containing multiple markers. Below is an example of what I have been working on. i ...

Mui Select fails to update value when defaultValue is specified

I am using a select component from the MUI React library along with react-hook-form and controller. I have set a default value in the controller to use the reset function, but I am unable to change the value when a default value is set. Everything works ...

Having trouble with importing SendInBlue into my NodeJS application?

Currently in the process of updating my Node app to utilize ES6 import modules over requiring files. Encountering difficulties while trying to integrate this change with SendInBlue for email functionality, resulting in the following error message: TypeEr ...

Storage can be shared globally in a React/Nextjs application

My current situation involves retrieving data through an application, however I am encountering 429 errors due to server limits restricting infinite requests. To address this issue, my plan is to fetch data nightly and store it in a centralized storage ac ...

Generating HTML elements on the server-side vs. retrieving data as JSON and dynamically creating elements using JavaScript

Looking to implement an AJAX search feature that will retrieve and display topics from a forum, including just the topic link and subject. My question is: Which method would be more efficient and quicker? Retrieve the threads list as a JSON string, co ...

Tips for selecting content for rendering with GetServerSideProps

Is there a way to display different text before and after a specific time without revealing all the content in the HTML? I've attempted using if-else logic within the component, but it ends up exposing text that should be hidden. Can getServerSideProp ...

What is the best way to invert the positioning of the li elements to move upwards?

https://i.stack.imgur.com/mZaoS.png Seeking assistance on adjusting the height of bars to start from the bottom and go upwards instead of starting from the top position and going downwards. The JavaScript code below is used to generate the li elements and ...

Calculate the total of all values associated with a dynamically generated key within an array of objects

I'm trying to calculate the sum of similar keys in an array of objects. Each object in the array will have some common keys, but not all arrays will share the same set of keys. I'm considering storing these keys in a separate array and then loopi ...

Phonegap - Retaining text data in a checklist app beyond app shutdown

This is my first time developing an app with Phonegap. I am looking to create a checklist feature where users can input items into an input field. However, I am struggling with figuring out how to save these items so that they remain in the checklist even ...

Rotating through elements in timed intervals

After exploring various examples of how to show/hide divs with a JavaScript timeout, I am still unable to resolve my specific issue. I currently have six divs that I want to cycle through sequentially every 10 seconds, starting with div #one. Although my ...

When the 'Show More' button is clicked, one Div will smoothly slide over another Div

I've been struggling for hours to find a way to make one DIV slide over another DIV below it instead of pushing it down. The setup is quite straightforward. I have a script that reveals more text when the 'Show More' button is clicked. Desp ...

There seems to be an issue with the function code error when calling it within the

When I attempt to run my code in this way, I encounter a compile time error stating that the expression statement is not an assignment or call... (within the else statement). What am I missing here to get it to work? I've made numerous attempts to ad ...

Rotate image in Vue3 using @click

I have a dashboard with a refresh button that I want to rotate 360 degrees every time it is clicked. How can I achieve this rotation effect on the image with each click of the refresh button? Below is the code snippet I have been working on, but it only r ...

Combining two arrays in JavaScript and saving the result as an XLS file

I have a question that I couldn't find an answer to. I need to merge two arrays and export them to an Excel file using only JavaScript/jQuery. Let's say we have two arrays: Array 1 : ["Item 1", "Item 2"] Array 2 : ["Item 3", "Item 4"] When the ...