简体   繁体   中英

ReactJS: Use setState at the end of a if statement inside a function

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?

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"};
    }
  }

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"}} />;
    })}     

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)} />

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>
    

在这种情况下你不应该使用 setState ,这是解决问题的好方法

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM