Skip to content

Conversation

@s-yadav
Copy link

@s-yadav s-yadav commented Aug 5, 2020

Hey @dahliacreative. While searching for micro react component for similar use case found your library. Great work. 👍

This is a draft PR with few improvements. Please let me know what do you think. I will add the test cases afterwards.

Changes:

  • Remove children when it's hidden. Improves React + DOM performance.
  • Add prop to keep the child when closed.
  • Use onTransitionEnd instead of setTimeout.
  • Forward remaining props on root element.

Also, I feel collapsable should be collapsible. Is this intentional? Should we keep a different name for it? I see there is already a library with react-collapsible name on npm.

Use this to ignore formatting changes.
https://github.com/dahliacreative/react-collapsable/pull/7/files?w=1

- Add prop to keep the child when closed.
- Use onTransitionEnd instead of setTimeout.
- Forward remaining props on root element
- @emotion-core is not required as peer dependency
src/index.js Outdated
speed: 0,
});

const [effectiveChildren, setChildren] = useState(children);
Copy link
Owner

Choose a reason for hiding this comment

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

Storing the children in state seems a bit over the top, could we not just add another option to state like showChildren: boolean and combine with keepChildrenOnClose to conditionally add the children in the JSX?

Copy link
Owner

Choose a reason for hiding this comment

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

Also, adding / removing children when opening / closing is causing more work for react as it's having to add / remove them from the DOM, so do you have any evidence of performance gains?

Copy link
Author

@s-yadav s-yadav Aug 21, 2020

Choose a reason for hiding this comment

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

Storing the children in state seems a bit over the top, could we not just add another option to state like showChildren: boolean and combine with keepChildrenOnClose to conditionally add the children in the JSX?

I guess adding showChildren will be just an extra prop. As most of the time lib user will pass isOpen value on showChildren. Also, it can't be handled outside as the effectiveChildren is set to null only after transition is finished. so then you will have to pass an onTransitionComplete prop, or onOpen/onClose prop to parent.

Also, adding / removing children when opening / closing is causing more work for react as it's having to add / remove them from the DOM, so do you have any evidence of performance gains?

So, this comes down to this question.
-> Do you want to pretender everything so when a user performs an action the transition is quick.?
-> Do you want to delegate the offscreen work when the user performs an action.?

On the first approach, you are paying the cost of rendering upfront for some content user may never see, probably on page load.
Plus as other things are going during page rendering, you are also adding some of the rendering time for an offscreen content.
This is valid on the update as well, why we need to do reconciliation (VDOM diffing) on offscreen content.

And on the second approach as onClick, you are doing relatively less work by shifting your work to onClick which will not be noticed. I feel this is a valid tradeoff to improve onscreen content performance. Sometime you may need a little bit of tinkering, but that you can do with keepChildrenOnClose prop.

Copy link
Owner

Choose a reason for hiding this comment

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

My main thoughts on this is accessibility and not hiding content from screen readers. Having a prop puts this in the hands of the developer, but I think having the children when closed should be the default.

Copy link
Owner

Choose a reason for hiding this comment

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

As for storing children in state, we can simply use a value stored in state to conditionally render the children and isOpen will override it.

I think storing children in state and removing them constantly would be inefficient and there is something we can do with a simple Boolean instead.

Copy link
Author

Choose a reason for hiding this comment

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

My main thoughts on this is accessibility and not hiding content from screen readers. Having a prop puts this in the hands of the developer, but I think having the children when closed should be the default.

display: none and visibility: hidden elements are not accessible on-screen reader as well. In Ideal situation content wise we see should be similar to what screen reader reads. Providing them two versions is anti-pattern for accessibility. Exceptions are visual contents like img, icons etc. But textual content-wise it should be same for screen reader and normal user.

Copy link
Author

@s-yadav s-yadav Sep 16, 2020

Choose a reason for hiding this comment

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

I think storing children in state and removing them constantly would be inefficient and there is something we can do with a simple Boolean instead.

Sure, I will update it boolean based.

src/index.js Outdated
}
return (
<div
{...restProps}
Copy link
Owner

Choose a reason for hiding this comment

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

This could lead to invalid props being passed down. I'm not sure it's needed as for custom styling you can just wrap it in a custom component which has it's own styling etc..

Copy link
Author

@s-yadav s-yadav Aug 21, 2020

Choose a reason for hiding this comment

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

My opinion:
This can be mentioned in the document. Forwarding non-component specific props to the root element can avoid the extra containers in dom elements if possible.

The actual use cases can definitely be solved other way as well. So I don't have a strong opinion on this. I will revert it back.

Copy link
Owner

Choose a reason for hiding this comment

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

Yeah I feel allowing for users to add their own class name to the wrapper would suffice.

src/index.js Outdated
import PropTypes from 'prop-types';

const Collapsable = ({
const Collapsible = ({
Copy link
Owner

Choose a reason for hiding this comment

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

Collapsable was intentional, you can spell it both ways and there is already a react-collapsible on NPM.

Copy link
Author

Choose a reason for hiding this comment

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

I will change this back.

- Use boolean flag instead of storing children in state.
- Remove spread props and rename the name to react-collapsable
@dahliacreative
Copy link
Owner

One other thing, can we update the read me to please? :)

@s-yadav
Copy link
Author

s-yadav commented Oct 7, 2020

@dahliacreative Sorry missed this. Sure will update.

speed: 0
})

const [keepChildren, toggleChildren] = useState(isOpen)
Copy link
Owner

Choose a reason for hiding this comment

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

can this just go into the state object above?

if (!isOpen) {
content.current.style.visibility = 'hidden'

if (!keepChildrenOnClose) {
Copy link
Owner

Choose a reason for hiding this comment

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

I would remove this and just add it to the conditional below {(keepChildren || keepChildrenOnClose) && children}
Perhaps also change keepChildren to something like displayChildren or shouldDisplayChildren feels a bit clearer.

? maxAnimationDuration
: time
content.current.style.visibility = 'visible'
toggleChildren(true)
Copy link
Owner

Choose a reason for hiding this comment

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

Again if we put this in the state object you can just set this below.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants