Monsieur Sam
Monsieur Sam

Reputation: 333

Show and Hide specific component in React from a loop

I have a button for each div. And when I press on it, it has to show the div with the same key, and hide the others. What is the best way to do it ? This is my code

class Main extends Component {
    constructor(props) {
      super(props);
      this.state = {
        messages: [
          { message: "message1", key: "1" },
          { message: "message2", key: "2" }
          ]
      };
    }
    handleClick(message) {
     //something to show the specific component and hide the others
    }
    render() {
      let messageNodes = this.state.messages.map(message => {
        return (
        <Button key={message.key} onClick={e => this.handleClick(message)}>
         {message.message}
        </Button>
        )
     });
     let messageNodes2 = this.state.messages.map(message => {
        return <div  key={message.key}>
           <p>{message.message}</p>
           </div>
     });
     return <div>
         <div>{messageNodes}</div>
         <div>{messageNodes2}</div>
            </div>
    }
}

Upvotes: 1

Views: 2824

Answers (3)

trailblazer
trailblazer

Reputation: 171

I cannot reply to @Omar directly but let me tell you, this is the best code explanation for what i was looking for! Thank you! Also, to close, I added a handleClose function that set the state back to false. Worked like a charm!

onCloseItem =(event) => {
    event.preventDefault();
    this.setState({
      openedItem: false
    });
  }

Upvotes: 0

Mirko Acimovic
Mirko Acimovic

Reputation: 506

Something like this. You should keep in state only message key of visible component and in render method you should render only visible component based on the key preserved in state. Since you have array of message objects in state, use it to render only button that matches the key.

class Main extends Component {
    constructor(props) {
       super(props);
       this.state = {
          //My array messages: [],
          visibleComponentKey: '',
          showAll: true
       };
       handleClick(message) {
          //something to show the specific component and hide the others
          // preserve in state visible component
          this.setState({visibleComponentKey : message.key, showAll: false});
      };
      render() {
        const {visibleComponentKey, showAll} = this.state;
        return (
          <div>
            {!! visibleComponentKey && ! showAll &&
               this.state.messages.filter(message => {
                    return message.key == visibleComponentKey ? <Button onClick={e => this.handleClick(message)}>{message.message}</Button>
        ) : <div /> })
            }
            { !! showAll &&
               this.state.messages.map(message => <Button key={message.key} onClick={e => this.handleClick(message)}>{message.message}</Button>)
            }
        </div>        
         );
}

}

I haven't tried it but it gives you a basic idea.

Upvotes: 1

Omar
Omar

Reputation: 3411

import React from "react";
import { render } from "react-dom";

class Main extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      messages: [
        { message: "message1", id: "1" },
        { message: "message2", id: "2" }
      ],
      openedMessage: false
    };
  }
  handleClick(id) {
    const currentmessage = this.state.messages.filter(item => item.id === id);
    this.setState({ openedMessage: currentmessage });
  }
  render() {
    let messageNodes = this.state.messages.map(message => {
      return (
        <button key={message.id} onClick={e => this.handleClick(message.id)}>
          {message.message}
        </button>
      );
    });
    let messageNodes2 = this.state.messages.map(message => {
      return (
        <div key={message.key}>
          <p>{message.message}</p>
        </div>
      );
    });
    const { openedMessage } = this.state;
    console.log(openedMessage);
    return (
      <div>
        {openedMessage ? (
          <div>
            {openedMessage.map(item => (
              <div>
                {" "}
                {item.id} {item.message}{" "}
              </div>
            ))}
          </div>
        ) : (
          <div> Not Opened</div>
        )}
        {!openedMessage && messageNodes}
      </div>
    );
  }
}

render(<Main />, document.getElementById("root"));

Edit zl2vxor7jm

The main concept here is this following line of code.

  handleClick(id) {
    const currentmessage = this.state.messages.filter(item => item.id === id);
    this.setState({ openedMessage: currentmessage });
  }`

When we map our messageNodes we pass down the messages id. When a message is clicked the id of that message is passed to the handleClick and we filter all the messages that do not contain the id of the clicked message. Then if there is an openedMessage in state we render the message, but at the same time we stop rendering the message nodes, with this logic {!openedMessage && messageNodes}

Upvotes: 2

Related Questions