As the title says, I am trying to a use setState inside of an if statement that is set inside a function and I'm having some issues.
I am trying to crete a series of Tab components, which take a function as inline style to determine if they should be visible or hidden. However, before I do the return for that function, I want to setState for the index of the rendered tab.
<Tab label="Tab 1" {...a11yProps(0)} style={displayTab(dataGames.length, 0)} />;
<Tab label="Tab 2" {...a11yProps(1)} style={displayTab(dataTvShows.length, 1)} />;
<Tab label="Tab 3" {...a11yProps(2)} style={displayTab(dataMovies.length, 2)} />;
<Tab label="Tab 4" {...a11yProps(3)} style={displayTab(dataSpotify.length, 3)} />;
Here is my displayTab function:
const displayTab = (dataLength:number, index:number) => {
if(dataLength === 0) {
return {display:"none"};
}else{
setTabIndex(index) //<----- this causes the Error!
return {display:"flex"};
}
}
However, whenever I run this, I get an error related to infinite render. My tabindex is just a simple number state const [tabIndex, setTabIndex] = useState<number>(0);
The Tab component is a part of Material UI.
How can I call my setTabIndex before I return {display:'flex'}
inside my function?
CodePudding user response:
Not sure what are you trying to achieve, but try below code
const displayTab = (dataLength:number, index:number) => {
if(dataLength === 0) {
return {display:"none"};
}else{
if(index !== tabIndex) setTabIndex(index)
return {display:"flex"};
}
}
CodePudding user response:
if you use a ternary operator like this it will only hide of stated tab and other able to display.
const [tab,setTab] = useState(0)
{["dataGames","dataTvShows","dataMovies","dataSpotify"].map((data,index)=>{
return <Tab label={`Tab ${index}`} {...a11yProps(index)} style={tab === index ?{display:"none"}:{display:"flex"}} />;
})}
CodePudding user response:
Do not put the seTabIndex
in the displayTab
function
const handleChange = (event, value) => {
setTabIndex(index)
};
<Tabs value={value} onChange={handleChange}>
<Tab label="Item One" />
<Tab label="Item Two" />
<Tab label="Item Three" />
</Tabs>
CodePudding user response:
Calling setTabIndex
in JSX isn't ideal, you know why? Your component renders and as soon as setTabIndex
is called it changes your tabIndex
state and then it re-renders
, thus ending in a loop.
I'm guessing that you're trying to keep an active index in the tabIndex
state, right?
You need to set the new tabIndex when a tab is clicked.
You need a handler for that, see handleChange
below.
const [tabIndex, setTabIndex] = React.useState(0);
const handleChange = (event: React.SyntheticEvent, newTabIndex: number) => {
setTabIndex(newTabIndex);
};
And then you should pass that handler to your Tabs
' onChange prop. Tabs
' value prop should receive tabIndex
state.
<Tabs value={tabIndex} onChange={handleChange}
Finally your displayTab
should calculate the styles like this.
const displayTab = (dataLength: number) => {
return {
display: dataLength === 0 ? 'none' : 'flex'
}
}
and should be called like this
<Tab label="Tab 1" {...a11yProps(0)} style={displayTab(dataGames.length)} />
CodePudding user response:
you should not use setState in this case, it's really bad way to solve the problem