Skip to content
This repository has been archived by the owner on Dec 5, 2024. It is now read-only.

Allow popper modfiers to be updated #302

Merged
merged 5 commits into from
Oct 12, 2019
Merged

Conversation

maclockard
Copy link
Contributor

Currently if a consumer updates the modifiers object prop, unless another prop also changes, the new modifiers are not applied. For example, if the passed modifier flip.enabled were to change from true to false, the popper doesn't pick up on that fact and continues allowing the popover contents to flip.

This PR allows for the Popper component to construct a new popper instance with the new modifiers if and only if the modifiers object changes (note: this is a reference comparison and not a value comparison).

I'm not that familiar with Popper.JS so if there is a more efficient way to make sure modifier changes get propagated to the underlying popover, please let me know!

As it stands, this could cause some unnecessary popper instance creation/destruction if the consumer isn't properly memoizing the modifiers object they pass. This could be partially solved by doing something like shallow comparing each modifier option object one by one instead of a top level reference comparison. Alternatively, if there is a more performant way to imperatively update an existing popper instance, that may be better to use to avoid as much churn. In fact, it would be even possible to combine both of these solutions as well.

@FezVrasta
Copy link
Member

I wonder if we could add a check in developement mode to warn in case the modifiers object has the same content but changed identity?

@@ -120,15 +130,7 @@ const Demo = enhance(
? ({ rotation, scale, opacity, top: topOffset }) => (
<Popper
placement="bottom"
modifiers={{
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the warning allowed me to catch us over updating the modifiers object in the demo here!

@maclockard maclockard force-pushed the patch-1 branch 2 times, most recently from 328d50a to 0ba3ea2 Compare September 16, 2019 23:53
@maclockard
Copy link
Contributor Author

done!

@FezVrasta
Copy link
Member

Cool thanks! I'm gonna test it out and merge it, it may take a few days unfortunately so I say sorry in advance!

src/Popper.js Outdated
) {

// develop only check that modifiers isn't being updated needlessly
if (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is Terser/Uglify/etc able to strip out this kind of condition?

Could we split it into two conditions to help the tools?

if (process.env.NODE_ENV === 'development') {
  if (this.props.modifiers !== prevProps.modifiers &&
      this.props.modifiers != null &&
      prevProps.modifiers != null &&
      shallowEqual(this.props.modifiers, prevProps.modifiers)
  ) {
    [...]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Currently if a consumer updates the `modifiers` object prop, unless another prop also changes, the new modifiers are not applied. For example, if the passed modifier `flip.enabled` were to change from `true` to `false`, the popper doesn't pick up on that fact and continues allowing the popover contents to flip.

This PR allows for the `Popper` component to construct a new popper instance with the new modifiers if and only if the `modifiers` object changes (note: this is a reference comparison and not a value comparison).

I'm not that familiar with Popper.JS so if there is a more efficient way to make sure modifier changes get propagated to the underlying popover, please let me know!

As it stands, this _could_ cause some unnecessary popper instance creation/destruction if the consumer isn't properly memoizing the `modifiers` object they pass. This could be partially solved by doing something like shallow comparing each modifier option object one by one instead of a top level reference comparison. Alternatively, if there is a more performant way to imperatively update an existing popper instance, that may be better to use to avoid as much churn. In fact, it would be even possible to combine both of these solutions as well.
@FezVrasta FezVrasta merged commit fc85cd1 into floating-ui:master Oct 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants