Reputation: 915
I want to dynamically open/close Collapse Elements independent of user interaction (to reveal a specific panel via a search result).
The Collapse react component has setActiveKey (and uses it on user click) but it is not exposed to the Collapse Node reference.
Is there anyway to open or close in a way that will not trigger a re-render?
I tried using state and props, but this always re-renders the full tree of nested Collapse components, which in my case takes over 3 seconds.
Posting the full code would be excessive here as there are many interdependent components nested. However the basic structure is visible here: https://codesandbox.io/s/nk64q4xy8p
I want to open a specific panel via a different user interaction. In the codepen that would be onChange of the select or clicking the button.
Upvotes: 6
Views: 18525
Reputation: 527
There is nothing bad to do it with state variable. Once state or props change, it will render the entire components and also the nexted ones.
But if there is any performance issue due to re-rendering, probably you should look into pure components and react lifecycle methods to improve the performance (or avoid re-render).
In addition, you can also use special props of Antd's Collapse destroyInactivePanel, it will destroy (unmount) inactive panels.
Code for your reference (https://codesandbox.io/s/y30z35p1vv?fontsize=14)
import React from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Collapse, Button, Select } from "antd";
const Panel = Collapse.Panel;
const text = `
A dog is a type of domesticated animal.
Known for its loyalty and faithfulness,
it can be found as a welcome guest in many households across the world.
`;
class AvoidRenders extends React.Component {
state = {
openPanel: "1"
};
onChange = key => {
this.setState({
openPanel: key
});
};
render = () => {
return (
<div>
<Select
dropdownMatchSelectWidth={false}
defaultValue="1"
onChange={this.onChange}
>
<Select.Option key="1" value="1">
Panel 1
</Select.Option>
<Select.Option key="2" value="2">
Panel 2
</Select.Option>
<Select.Option key="3" value="3">
Panel 3
</Select.Option>
</Select>
<Collapse activeKey={this.state.openPanel} destroyInactivePanel={true}>
<Panel header="This is panel header 1" key="1">
<Text1 />
</Panel>
<Panel header="This is panel header 2" key="2">
<Text2 />
</Panel>
<Panel header="This is panel header 3" key="3">
<Text3 />
</Panel>
</Collapse>
</div>
);
};
}
class Text1 extends React.PureComponent {
componentWillUnmount = () => {
console.log("Destroyed 1");
};
componentWillUpdate = () => {
console.log("Updated 1");
};
render = () => (
<p>
{console.log("Rendered 1")}
{text}
</p>
);
}
class Text2 extends React.PureComponent {
componentWillUnmount = () => {
console.log("Destroyed 2");
};
componentWillUpdate = () => {
console.log("Updated 2");
};
render = () => (
<p>
{console.log("Rendered 2")}
{text}
</p>
);
}
class Text3 extends React.PureComponent {
componentWillUnmount = () => {
console.log("Destroyed 3");
};
componentWillUpdate = () => {
console.log("Updated 3");
};
render = () => (
<p>
{console.log("Rendered 3")}
{text}
</p>
);
}
ReactDOM.render(<AvoidRenders />, document.getElementById("container"));
I hope, this would help.
Upvotes: 5