8

So, I am trying to figure out the best way to do this:

Showing a modal or hiding a modal in react. On my main page I have a lot of photos and my current state setup is:

export default class Main extends TrackerReact(Component) {
  constructor(props) {
   super(props);
   this.state = {
     showModal: false,
     modalPhoto: {},
   };

   this.close = this.close.bind(this);
   this.open = this.open.bind(this);
}
close() { this.setState({ showModal: false }); } // basic modal close
open(e) {
  this.setState({ modalPhoto: e });
  this.setState({ showModal: true });
}

When I set showModal to true, it passes to the bootstrap-react modal:

<Modal
  show={this.props.show} >
  // ...loads modalPhoto form main state.modalPhoto
</Modal>

Problem: Every time I open the modal, it changes the main state and re-renders the main page. What is the best practice way to stop this re-render from happening? I tried:

// in the main component
shouldComponentUpdate(nextProps, nextState) {
  if (this.state.showModal !== nextState.showModal) {
    return false;
  } else {
    return true;
  } // PS. I know this is wrong, but I was desperate...

I was also considering going around the outside with jquery and manually show the modal or hide the modal and thus not change state. The problems with this are obvious, Unmount and ReceiveProps is hard to maintain.

I also know that TrackerReact package will re-render if data changes, but no data should be changing with modal open and close.

Thoughts?

Daltron
  • 1,729
  • 3
  • 20
  • 37
  • This is how react is designed to work. Is there an issue with causing a top level render call? – Andy Ray Apr 04 '17 at 21:59
  • Does the modal need to be at the base class? can it be a child component? that being said with the current setup your modal can only show if a render happens which would be a render of everything else. – John Ruddell Apr 04 '17 at 21:59
  • 1
    just as a quick optimization. change your open function to call setState only once `this.setState({ showModal: true, modalPhoto: e });` its twice as performant! two setstate calls will do two lifecycles (including a render). But you can make it one setState :) – John Ruddell Apr 04 '17 at 22:00
  • Also are you using a framework like Redux? you can work around renders with something like this by only subscribing to certain fields of your store that are related to a modal. – John Ruddell Apr 04 '17 at 22:08
  • 3
    Actually, the two `setState` calls will not result in two re-renders. They will be merged and applied as one. ["setState() does not immediately mutate this.state but creates a pending state transition"](https://facebook.github.io/react/docs/react-component.html#setstate) – btidwell Apr 04 '17 at 22:08
  • I must agree with the first comment, however. Visual state is changing (you are opening a modal), and thus you would expect a re-render. Blocking the render as you have in your example will result in no modal appearing at all. Why is a re-render bad? – btidwell Apr 04 '17 at 22:12
  • 1
    @btidwell nice! thats good to know. Still better to merge the two together though for more succinct code :) – John Ruddell Apr 04 '17 at 22:12
  • @JohnRuddell agreed! It's better practice to merge them if you can. I just wanted to point it out because it's helpful to understand exactly what `setState` is doing. Otherwise, it can cause some very unexpected behavior. – btidwell Apr 04 '17 at 22:18
  • @btidwell completely agree, appreciate you bringing it up :) I think if the render is really an issue (not sure why it would be) you could create a component that is rendered from the main that you connect via redux to a store. manage the open state in the store and only subscribe to the modal store info on the modal component. that way the only renders that would run would be from the modal component. A modal is ontop of everything so fixed positioning could make it look normal. – John Ruddell Apr 04 '17 at 22:21
  • Okay, I think I can get away with attaching these modals to the navigation bar. The only tricky part is translating the ` – Daltron Apr 05 '17 at 00:33

1 Answers1

3

Maybe you should consider using a component to wrap your modal and manage the state. Your main component would not be updated anymore.

As said in the comments above, refreshing the view as soon as the state has been updated is the way React works

Dan Abramov has written a very interesting answer on Stack Overflow on how to deal with Modals with a redux state: How can I display a modal dialog in Redux that performs asynchronous actions?

Try to get some inspiration from this article.

Hope this helps!

Community
  • 1
  • 1
rouflak
  • 154
  • 5