Reputation: 1508
I have a component which, among other things, has a controlled text field used for filtering, and the value of the text field is stored in the component's state.
I discovered yesterday that if I render multiple instances of that component inside tab panes of semantic-ui-react
's Tab
component, the states seem to be shared. Meaning, if I type into Tab A's text field then switch to Tab B, the text field there has the same content as Tab A, even though I never typed into it.
However, if I render multiple instances outside semantic-ui-react
's Tab
component, the state is not shared. Typing text into one field has no effect on any other field.
Ideally I do not want the components to share state (or do whatever weird thing they're doing to have the same value). I want the value of each component's text field to be independent of the other.
I feel like it has something to do with the components not being rendered until I change to their tab, but I can't get much further than that. I'm not sure if this is a problem specific to semantic-ui-react
- in fact I suspect if I create my own tab component it might have the same behavior. Demo code is below, and I set up a basic codepen that illustrates the problem, can anyone shed some light on the subject?
codepen demo: https://codepen.io/MikeWillis/pen/XWMXRoJ
js code:
const Filter = (props) => {
const [filter,setFilter] = useState("");
return (
<React.Fragment>
<label>
{props.name}:{" "}
<input
type="search"
value={filter}
onChange={(event)=>setFilter(event.target.value)}
/>
</label>
</React.Fragment>
)
};
const TabbedFilters = (props) => {
const panes = [
{ menuItem: 'Filter A', render: () => <Tab.Pane><Filter name="Filter A" /></Tab.Pane> },
{ menuItem: 'Filter B', render: () => <Tab.Pane><Filter name="Filter B" /></Tab.Pane> }
];
return (
<div style={{border: "1px solid #ccc", margin: "5px", padding: "3px"}}>
<p><b>These filters WILL share state. Not cool.</b></p>
<Tab panes={panes} />
</div>
)
};
const UnTabbedFilters = (props) => {
return (
<div style={{border: "1px solid #ccc", margin: "5px", padding: "3px"}}>
<p><b>These filters will NOT share state. Cool, that makes sense.</b></p>
<div style={{marginLeft: "15px"}}>
<Filter name="Filter A" />
<br />
<Filter name="Filter B" />
</div>
</div>
)
};
const AllFilters = (props) => {
return (
<React.Fragment>
<UnTabbedFilters />
<TabbedFilters />
</React.Fragment>
)
};
ReactDOM.render( <AllFilters />,document.getElementById("root"));
Upvotes: 1
Views: 1190
Reputation: 3875
Add the key prop. This will help React diff the DOM properly.
const TabbedFilters = (props) => {
const panes = [
{ menuItem: 'Filter A', render: () => <Tab.Pane><Filter key="filter-a" name="Filter A" /></Tab.Pane> },
{ menuItem: 'Filter B', render: () => <Tab.Pane><Filter key="filter-b" name="Filter B" /></Tab.Pane> }
];
return (
<div style={{border: "1px solid #ccc", margin: "5px", padding: "3px"}}>
<p><b>These filters WILL share state. Not cool.</b></p>
<Tab panes={panes} />
</div>
)
};
Upvotes: 2