Avoid `OverlayTrigger` from unmounting overlay - reactjs

How do I stop the OverlayTrigger component from react-bootstrap from unmounting its overlay component when the onHide prop is called? This is the component that shows the Popover. It is not an issue with Popover since setting overlay={<ComplexComponent />} causes the same issue where ComplexComponent is mounted every time the OverlayTrigger is triggered.
This is a simplified version of what I'm attempting:
const overlay = (<Popover id="some-random-id">
<ComplexComponent />
</Popover>;
<OverlayTrigger
trigger={['hover', 'focus']}
placement="top"
overlay={overlay}
>
<span>trigger label</span>
</OverlayTrigger>
The reason I need to just hide the overlay instead of unmounting it is that ComplexComponent makes service calls on componentWillMount and takes a considerable amount of time to do that initial fetch. I've considered using refs but haven't come up with a good enough strategy.

Related

Prevent antd component from rerender

I have an antd collapse component which is wrapped by react-query and I'm enabling refetchInterval in my query, so the issue is that antd Collapse component is restored to its initial state(closed) automatically after opening when the time which I gave to RefetchInterval is set, so is there a way to prevent this behavior?
You can pass the key of the Collapse.Panel in the defaultActiveKey of the Collapse component.
<Collapse defaultActiveKey={['1']}>
<Collapse.Panel header="panel1" key="1">
//some components
</Collapse.Panel>
</Collapse>
OR
You can use a state and pass it on the activeKey props of the Collapse.
For more information: https://ant.design/components/collapse/#API

What is causing my component to unmount?

I'm making an app where I have an Overlay component and a Map component rendering behind it just like this:
<div>
{showOverlay && <Overlay />}
<Map /> // this component should mount once
</div>
The overlay is shown to let the map load underneath but when I remove the Overlay (set showOverlay to false here) the Map component re-load.
At first I thought the Map component was just re-rendering, but after some digging I discovered that the component was actually re-mounting.
If I log in the componentWillMount, componentWillUnmount and render methods, the log appear in that order (which seems contradictory)
render
willUnmount
willMount
The parent does not re-mount, only the Map component do.
The Map component just render a div that reference a mapbox-gl-js map (like this https://gist.github.com/tristen/5c4b346ae38892f732504e6785d87057#file-map-js)
What can cause my component to re-mount itself like that ?
Thanks !

Collapsible accordion onClick and open handlers

I am using this: https://react-materialize.github.io/#/collapsible.
Is there a way to programmatically make a react-materialize accordion open other than clicking on it itself?
I am trying to add an onClick handler to so that I can do a setState when one of my react-materialize collapsible accordions is selected so that I can do something based on what that state is and render content into that accordions popout (conditional rendering and for another purpose purpose.
I have 3 CollapsibleItems and this.changeBoardType is called 6 times when the page renders, if I do a setState inside it I get caught in an infinite loop:
Maximum update depth exceeded. This can happen when a component
repeatedly calls setState inside componentWillUpdate or
componentDidUpdate. React limits the number of nested updates to
prevent infinite loops.
NOTE: the same thing happens if I use their built in onSelect prop on the <CollapsibleItem onSelect={this.changeBoardType("single")} />
<Collapsible accordion>
<CollapsibleItem onClick={this.changeBoardType("single")} header='Single Hand' icon='filter_1'>
<Row>
<Input s={12}
name="singleHand"
type="select"
label="Position"
value={this.state.singleHand}
onChange={this.handleChange}>
...
If you are trying to pass an argument to an event handler such as onClick or onSelect, you need to do it like this:
<CollapsibleItem onClick={() => this.changeBoardType('single')} ...>
Calling an anonymous function that returns your changeBoardType function will prevent the infinite setState loop

Testing for text contained in React component with Enzyme and Jest

For my React component I have the following:
const ArchiveButton = ({collection, onClick}) => {
return (
<span>
{ collection.archived &&
<Button bsStyle="link" onClick={onClick}><i className="fa fa-rotate-left" /> Unarchive</Button>
}
{ !collection.archived &&
<Button bsStyle="link" onClick={onClick}><i className="fa fa-archive" /> Archive</Button>
}
</span>
);
};
I'm attempting to test by passing in different values for collection.archived and I want to check for the existence of the text "Unarchive" vs "Archive". When I do a wrapper.find('Button') and try and check against .text() it is just <Button /> and the only way I've figured out how to test it is:
const wrapper = shallow(<ArchiveButton onClick={onClick} {...props}/>);
let button = wrapper.find('Button').prop('children');
expect(button[1]).toMatch(/\sUnarchive/);
Seems a bit off though, not sure. Thanks!
It's because you're using shallow rendering, so your nested Button component doesn't get rendered. As you've seen, you can access the nested component props to test the values you pass to it.
If you prefer to have the button content rendered, use normal rendering instead.
Note that the nested Button is not a normal DOM element, which would be rendered anyway even if you use shallow rendering, but it's instead a component itself.
If you think about it, if you don't use shallow rendering in your case, you're not really unit-testing your component, as you're also asserting something about the Button component. If you use shallow rendering and access the props of the nested component, you're really just testing that your code is calling the Button component with the correct arguments, and you're not making any assumptions as how the Button component will render.
This is normally what you want to do in a unit test.

React — open modal in body from nested component

React noobie... I'm trying to figure out the "correct" way to handle modals in a React App... i.e. where the modal container should live and where the children should live and whether I should use state or props to handle the open/close. Also, how to open them relative to the document body no matter where they live.
My overall App structure:
<App>
<Sidebar />
<MainConstainer>
<ChildPage>
<ChildList>
<BtnModalTrigger>
<button onClick={open.modal.relative.to.doc.body}>Open Modal</button>
</BtnModalTrigger>
</ChildList>
<Modal />
</ChildPage>
</MainConstainer>
</App>
I have the Modal component in the child page hidden, and the trigger button in the list and then the "Close modal" button is in modal itself. I'm not sure where to put my isOpen and isClosed functions or how to pass the onClicks up and down the component tree.

Resources