ReactJS - Hide other Popovers when a Popover opens

1

I have a component that creates a series of other components that contain information, that information I would like to show in a popover

I am using reactstrap to streamline the process, this is the component

import React, { Component } from 'react';
import '../Assets/css/grayscale.css';
import { Collapse, Button, CardBody, Card } from 'reactstrap';


class Jouers extends Component {
    constructor(props){
        super(props);
        this.state = {
            jouers:[],
            collapse: []

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

 toggle(ide) {
    let newState = Object.assign(this.state.collapse)
    for (var i = 0; i < newState.length; i++) {
        if(this.state.jouers[i].id === ide){
            newState[i]=false;
        }else{
            newState[i]=true;
        }
    }
    this.setState({ collapse: newState });
  }

    componentDidMount(){
        console.log(this.props.location.param1);
        fetch(this.props.location.param1, {
            method: 'GET',
            headers: {
                'X-Auth-Token': '3b7136ad76ce4b0cacd7e1b02d50870f',
            }
        })
        .then(res => res.json())
        .then(res => {
            this.setState({
             jouers: res.players,
             collapse: new Array(res.players.length).fill(true)
            });
        })
        .catch(error => {
            console.log('error dude, desolé');
        })
    }



    render () {
        const tailleArray = this.state.jouers.length;
        console.log(this.state.jouers);
        return (
        <div>
            <header className="ligues">
             <div className="intro-body">
                <div className="container">
                  <div className="row">
                    <div className="col-lg-8 mx-auto">
                      <h1 className="brand-heading">Ligues Football</h1>
                      <a href="" className="btn btn-circle js-scroll-trigger">
                        <i className="fa fa-angle-double-down animated"></i>
                      </a>
                    </div>
                  </div>
                </div>
              </div>
            </header>
            <h1>Jouers Page</h1>
            <div className="container">
            { 
                tailleArray>0 ? (

                    <div className="row">
                        {       
                            this.state.jouers.map((p,i) => {
                                return(
                                    <div className="col-md-3" key={p.id}>
                                        <div className="hello">
                                          <img className="card-img-top" src="https://cdn0.iconfinder.com/data/icons/cup/154/football-shield-club-sport-512.png" alt="Card image cap"/>
                                          <div className="card-body">
                                            <h5 className="card-title black"> {p.name} </h5>
                                           <Button color="primary" onClick={this.toggle} style={{ marginBottom: '1rem' }}>Toggle</Button>
                                            <Collapse isOpen={this.state.collapse[p.id]}>
                                              <Card>
                                                <CardBody className="noir">
                                                Anim pariatur cliche reprehenderit,
                                                 enim eiusmod high life accusamus terry richardson ad squid. Nihil
                                                 anim keffiyeh helvetica, craft beer labore wes anderson cred
                                                 nesciunt sapiente ea proident.
                                                </CardBody>
                                              </Card>
                                            </Collapse>
                                          </div>
                                        </div>
                                    </div>
                                );
                            })
                        }
                    </div>
                ):(
                    <div className="centered"><h1>pas de jouers</h1></div>
                )
            }
            </div>
        </div>
        );
    }
}

export default Jouers;

But ... when I click on the button of one of the elements, all popovers open when I only want to see one.

I tried using the KEY property of the map function, but still doing the same thing

    
asked by Ernesto Emmanuel Yah Lopez 18.06.2018 в 00:50
source

1 answer

1

That is the expected behavior given your implementation.

Your Jouers component has a list of jouers but a single boolean that determines whether they are collapsed or not. When you create the list of jouers in the render you are indicating

 <Collapse isOpen={this.state.collapse}>

That is, all the jouers of your mapping are going to have the Collapse element rendered or not, you have no way to discriminate like this, you are taking the Boolean only and shared.

You can solve it by simply having an array of Booleans for each jouer of your list.

constructor(props){
        super(props);
        this.state = {
            jouers:[],
             collapse: [] // manejamos a nivel de cada jouer

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

When you mount the component and initialize the jouers you should indicate that all are collapsed (initial state)

componentDidMount(){
        console.log(this.props.location.param1);
        fetch(this.props.location.param1, {
            method: 'GET',
            headers: {
                'X-Auth-Token': '3b7136ad76ce4b0cacd7e1b02d50870f',
            }
        })
            .then(res => res.json())
            .then(res => {
                this.setState({
                 jouers: res.players
                 collapse: new Array(res.players.length).fill(true);
                });
            })
            .catch(error => {
                console.log('error dude, desolé');
            })
    }

Then, when you invoke the toggle function, indicate by parameter which jouer is:

 toggle(jouerId) {
    let newStateCollapsed = ... this.state.collapse;
    // Recibo en la funcion toggle el id del Jouer a mostrar
    for(let i=0;i<this.state.jouers.length; i++){
        // obtengo el jouer para cada iteracion de la funcion map cuando es invocada, chequeo según el id del jouer (este dato es algun valor que hace unico a tu jouer, puede ser simplemente un valor autoincremental de 0 a el largo del array de jouers
        if(this.state.jouers[i].id === jouerId){
            newStateCollapsed[i] = false; // lo marco como visible 
        }else{
           // los otros se ocultan
            newStateCollapsed[i] = true;
        }

    }

    this.setState({ collapse: newStateCollapsed  }); // Seteo nuevo estado donde el Jouer clickeado no esta colapsado
  }

For this when you do the mapping you must pass something that identifies the Jouer, in this case I call it Id, but it would be a piece of information that is part of your Jouer and that makes it unique.

The conflicting line would now be:

<Collapse isOpen={this.state.collapse[p.id}>

That is, each Collapse will be open or not depending on the Boolean value of the array.

    
answered by 18.06.2018 в 01:10