In ReactJS modal body and footer showing twice while loading data form API

I am trying to load data from laravel route with axios request in modal, but the modal body and btns showing twice inside the modal. Why does that happen? Below is my code for reference.

class PopUp extends React.Component{
 constructor(props) {
    super(props);
    this.state={
        singleProject:[],
        errs:''
    }
}

singleData(){
    const token = document.querySelector('meta[name="csrf-token"]');
    const fd={
        '_token':token.content,
        'id':this.props.id,

    }
    return fd;
}
componentDidMount() {
    //reuest for services
    Axios.post('/single/project',this.singleData()).then(resp =>{
        this.setState({singleProject:resp.data});
        console.log(resp.data)
    }).catch(err=>{
        this.setState({errs:err})
        // console.log(err)
    })


}



render() {
    const project= this.state.singleProject;
    return(
        <div>
            <Modal show={this.props.show} onHide={this.props.onHide} size="xl" aria-labelledby="contained-modal-title-vcenter" centered>
                {
                    project.map(data=>(
                      <React.Fragment key={data.id}>
                                <Modal.Header closeButton>
                                    <Modal.Title id="contained-modal-title-vcenter">
                                        {data.project_name}
                                    </Modal.Title>
                                </Modal.Header>
                                <Modal.Body  >
                                <h4>Centered Modal</h4>
                            <p>
                            Cras mattis consectetur purus sit amet fermentum. Cras justo odio,
                            dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac
                            consectetur ac, vestibulum at eros.
                            </p>
                            </Modal.Body>
                            <Modal.Footer>
                                <a href={data.project_live_link} className="btn btn-primary">live</a>
                                <a href={data.project_github_link} className="btn btn primary">github</a>
                            </Modal.Footer>
                  </React.Fragment>
                    ))
                }

            </Modal>

        </div>
    )
}}
export default PopUp;

and here is an image of what I am getting on rendering click to view modal showing data

i have tried loading complete data and now i am showing you only by adding project name but modal data is already twice showing under project.map area please guide me why is it happening

Answers:

Answer

So you are fetching the data, storing it in the local store, and the fetched data is in the form of an Array.

Furthermore you are mapping over this fetched array and for each item in the array you are returning a React Fragment.

This React Fragment is rendering Modal.Header, Modal.Body, Modal.Footer.

Instead of this approach, you should consider a different approach. Basically you need to have all the projects displayed in the modal. So think of each project as a

Modal.Header and Modal.Footer should be outside the map function.

<Modal>
 <Modal.Header>
  Modal Heading
 </Modal.Header>
   {data.map(project => (
      <div class='project'>
       <div class='name'>{project.name}</div>
       <div class='description'>{project.description}</div>
       <div class='project_link'>
         <div class='live_link'>{data.live_link}</div>
         <div class='github_link'>{data.github_link}</div>
       </div>
      </div>
    )})}
 <Modal.Footer>
  Footer Info
 </Modal.Footer>
</Modal>

UPDATE: Make the below changes to your componentDidMount call. I have added some comments before you set the state after you get the results.

componentDidMount() {
//reuest for services
Axios.post("/single/project", this.singleData())
  .then(resp => {
    //here the data you are getting is in the form of an array.
    //but you don't need that entire array.
    //all you need is the object sitting at index 1
    //so instead of setting {resp.data} set {resp.data[1]}
    this.setState({
       singleProject: (resp.data && resp.data[1]) || {} 
    });
    console.log(resp.data);
   })
  .catch(err => {
    this.setState({ errs: err });
    console.log(err);
  });
 }

After this, you can use the project data normally as you would with any other object. I hope this solves the issue. If not, please share the exact code that you are using currently.

Answer

Your state.singleProject is an array, seems like your are getting two items from the backend, so when you do singleProject.map you end up creating two modal bodies and footers.

You should instead change state.singleProject to {} and have your API to return an object and replace your modal code as below:

    <Modal show={this.props.show} onHide={this.props.onHide} size="xl" aria-labelledby="contained-modal-title-vcenter" centered>
          <React.Fragment key={project.id}>
            <Modal.Header closeButton>
              <Modal.Title id="contained-modal-title-vcenter">
                {project.project_name}
              </Modal.Title>
            </Modal.Header>
            <Modal.Body  >
              <h4>Centered Modal</h4>
              <p>
                Cras mattis consectetur purus sit amet fermentum. Cras justo odio,
                dapibus ac facilisis in, egestas eget quam. Morbi leo risus, porta ac
                consectetur ac, vestibulum at eros.
                            </p>
            </Modal.Body>
            <Modal.Footer>
              <a href={project.project_live_link} className="btn btn-primary">live</a>
              <a href={project.project_github_link} className="btn btn primary">github</a>
            </Modal.Footer>
          </React.Fragment>

        </Modal>

Hope it helps!

Tags

Recent Questions

Top Questions

Home Tags Terms of Service Privacy Policy DMCA Contact Us

©2020 All rights reserved.