Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Change items in list in React when an item has been clicked

Tags:

I'm quite new to ReactJS and I have trouble understand how different components can communicate with each other.

I do have a component that will render a list and each list item is a different component. I want to keep the components as small as possible.

Now, each list item can have a property named active and if the property is set to true, an additional class is added.

This is the class that defines a single item in the component.

See this below code for my component defining a single list item:

export default class OfficeRibbonTab extends React.Component {

  constructor(props) {
    super(props);

    this.state = {
      active: props.active ? props.active : false
    }

    // Assign all the correct event handlers.
    this.setActive = this.setActive.bind(this);
  }


  setActive() {
    this.setState({active: true});
  }

  render() {
    // When the tab is defined as active, add the "active" class on it.
    if (this.state.active)
    { var tabClassName = "active"; }

    return <li onClick={this.setActive} className={tabClassName}>{this.props.tabName}</li>;
  }
}

So, I have propery active which is passed to this component, which I store in the components state. When I click the list item, I set to state of the current item to be active. The problem is that I want all the other list items to become inactive, thus setting the state of active to false.

The code below is an overview of my list:

export default class OfficeRibbon extends React.Component {

  constructor(props) {
    // Call the 'base' constructor.
    super(props);
  }

  render() {
    var tabs = [];

    // Loop over all the tab elements and define how the element should be rendered.
    for (var i = 0; i < this.props.dataSource.tabs.length; i ++)
    {
      if (i == 1)
      { tabs.push(<OfficeRibbonTab active={true} key={this.props.dataSource.tabs[i].name} tabName={this.props.dataSource.tabs[i].name}></OfficeRibbonTab>); }
      else
      { tabs.push(<OfficeRibbonTab key={this.props.dataSource.tabs[i].name} tabName={this.props.dataSource.tabs[i].name}></OfficeRibbonTab>); }
    }

    return (<div>
      <div className="wrap-top">
        <OfficeRibbonTitle title={this.props.title}/>

        <ul className="tabs">
          {tabs}
        </ul>

      </div>

    </div>);
  }
}

It doesn't seem like rocket science, but I want to do it the React way without re-inventing the wheel.

Anyone who can guide me in the right direction?

Kind regards

like image 227
Complexity Avatar asked Jun 04 '16 19:06

Complexity


People also ask

How do you update list items in React?

To implement the change of item on click, we will create the list data as a state in react by using the useState hook. Then on onClick we will change the item. Step 3: Create folder components inside src folder of react project directory and inside the components folder create files List. jsx.

How do I create a dynamic list in React?

To render a list dynamically in React, we start by adding a property to the state object. We can populate that property with an array of strings like so. Great. Now we want to move to the render() method to render each list item dynamically.

How do I change the onClick component in React?

We have to set initial state value inside constructor function and set click event handler of the element upon which click, results in changing state. Then pass the function to the click handler and change the state of the component inside the function using setState.

How do I make a list editable in React?

js - Input editable UI import React, { useState } from "react"; import Editable from "./Editable"; function App() { // State for the input const [task, setTask] = useState(""); /* Enclose the input element as the children to the Editable component to make it as inline editable.


1 Answers

It looks like OfficeRibbonTab manages its own state, which is fine, but it never informs its parent component of the state change. The most common approach would be to supply a callback function to each child component, so that it can then communicate back to the parent:

For example, OfficeRibbon will now contain a function handleTabSelect that gets passed down as a prop to each OfficeRibbonTab. And in OfficeRibbonTab, when a tab is clicked, you simply invoke the callback, and pass in the selected tab's index or id:

OfficeRibbonTab.jsx

 setActive(tabIndex) {
    this.props.handleTabSelect(tabIndex);
 }

OfficeRibbon.jsx

 handleTabSelect(tabIndex) {
    this.setState({activeIndex: tabIndex});
 }

Now in OfficeRibbon, you update your state to set the activeIndex or activeId, again either by the index or an identifier of your choosing. By setting state in OfficeRibbon, we necessarily force a render() of its children. As a result, we simply match the index of the iterator with the activeIndex of your state, when we iterate in render():

<OfficeRibbonTab active={index === this.state.activeIndex} onClick={this.handleTabSelect} ... />
like image 112
lux Avatar answered Sep 28 '22 02:09

lux