MountainConqueror
MountainConqueror

Reputation: 602

React-router-modal strange behavior - I need two clicks to go back, should be just one

I used this npm package => react-router-modal( doc )

And here (click) in that example it takes only one click to go back from modal, but in my case, I must do the mouse click two times to go back, and I don't know why...

So maybe someone here can help me answer that question.

Quick demo of that issue -> https://youtu.be/szRC_K10pyA

Full project code -> github

Two the most important components below:

Component BeerListItem

import React, { Component } from 'react';
import Card, { CardContent } from 'material-ui/Card';
import { ModalContainer, ModalRoute } from 'react-router-modal';
import { BrowserRouter, Link } from 'react-router-dom';
import 'react-router-modal/css/react-router-modal.css';
import './style.css';

import BeerProfile from '../BeerProfile';

class BeerListItem extends Component {
  constructor(props) {
    super(props);

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

  beerProfile() {
    const { beer } = this.props;
    return (
      <div>
        <BeerProfile beer={beer} />
      </div>
    );
  }

  render() {
    const { beer } = this.props;
    let cutStr = '';

    if (beer.name.length >= 27) {
      cutStr = `${beer.name.slice(0, 26)}...`;
    } else {
      cutStr = beer.name;
    }

    return (
      <BrowserRouter>
        <div>
          <Link to={`/details/${beer.id}`}>
            <Card raised className="BeerListItem-main-card">
              <CardContent>
                <img
                  src={beer.image_url}
                  alt="beer"
                  className="BeerListItem-img"
                />
                <div className="BeerListItem-h2-and-p-container">
                  <h2 className="BeerListItem-h2">{cutStr}</h2>
                  <p className="BeerListItem-p">{beer.tagline}</p>
                </div>
              </CardContent>
            </Card>
          </Link>

          <ModalRoute
            className="test-modal test-modal-foo"
            path={`/details/${beer.id}`}
            parentPath="/"
            component={this.beerProfile}
          />

          <ModalContainer />
        </div>
      </BrowserRouter>
    );
  }
}

export default BeerListItem;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Component BeerProfile

import React, { Component } from 'react';
import { Modal } from 'react-router-modal';
import 'react-router-modal/css/react-router-modal.css';
import './style.css';

class BeerProfile extends Component {
  constructor(props) {
    super(props);

    this.state = {
      show: true,
    };
    this.handleBackClick = this.handleBackClick.bind(this);
  }

  handleBackClick() {
    this.setState({ show: false });
  }

  render() {
    console.log(this.props);

    const { id } = this.props.beer;
    return (
      <div>
        {this.state.show && (
          <Modal onBackdropClick={this.handleBackClick}>
            <h3>Child elements</h3>
            <p>{id}</p>
          </Modal>
        )}
      </div>
    );
  }
}

export default BeerProfile;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Upvotes: 0

Views: 579

Answers (1)

Cagri Yardimci
Cagri Yardimci

Reputation: 3529

I think I figured it out.

So when your modal is rendered, this is the console log I get, enter image description here

So basically, two mounting occurs instead of one.

When I checked the codebase, I see that inside of BeerListItem, you use ModalRoute component from the package.

 <ModalRoute
   className="test-modal test-modal-foo"
   path={`/details/${beer.id}`}
   parentPath="/"
   component={this.beerProfile}
 />

And this.beerProfile renders the following

{this.state.show && (
  <Modal onBackdropClick={this.handleBackClick}>
    <h3>Child elements</h3>
    <p>{id}</p>
  </Modal>

Modal is also from the package itself

From documentation => ModalRoute

ModalRoute A react-router Route that shows a modal when the location pathname matches.

=> Modal

Modal Renders its contents in a modal div with a backdrop. Use Modal if you want to show a modal without changing the route.

So basically it is an either/ or situation. If you want a modal with a changing url, you should use ModalRoute. If you only want modal, you should use Modal.

To my understanding, when you pass a component prop to ModalRoute it automatically wraps this components with a Modal

So what you need to do is, replacing

<div>
  {this.state.show && (
    <Modal onBackdropClick={this.handleBackClick}>
      <h3>Child elements</h3>
      <p>{id}</p>
     </Modal>
   )}
 </div>

with

  <div>
    <h3>Child elements</h3>
    <p>{id}</p>
  </div>

Ah also one small thing, you also need to get rid of className

<ModalRoute
            className="test-modal test-modal-foo"

when I check the codebase, I couldn't find styling related to these two.

After these changes, should work the way you expect.

One tip, ModalRoute also accepts props props. So instead of passing this.beerProfile you can do the following and it should also work

<ModalRoute
  path={`/details/${beer.id}`}
  props={this.props}
  parentPath="/"
  component={BeerProfile}
/>

Currently in my local, it's working as expected. Please try and let me know if it also works for you or not.

Upvotes: 1

Related Questions