Giter VIP home page Giter VIP logo

Comments (7)

joepvl avatar joepvl commented on July 20, 2024 1

@joepvl So you mean react-tabs cache by default if all props are same on next visit ?

Which part of my comment led you to that conclusion? I'm going to assume by "next visit" you mean the next time a TabPanel is selected.

Just to be clear, memo has no explicit interaction with this library. All react-tabs does is:

  • by default: render (as in mount!) only the content of the TabPanel that corresponds to the selected index
  • if you pass forceRenderTabPanel to Tabs: always render the content of all TabPanels. This means that they will only be mounted once β€” of course you should still wrap them in memo if you don't want them to be rerendered when Tabs is rerendered.
  • if you pass forceRender to a subset of your TabPanels: always render the content of all TabPanels that have the forceRender prop, in addition to that of the currently active TabPanel if that does not have the forceRender prop

I think there may be a fundamental misunderstanding here β€” there is a difference between components rendering and components rerendering. The word "render" in forceRenderTabPanel refers to mounting the component, so that the VDOM tree will look like this (simplified for illustration purposes):

Example 1, without `forceRenderTabPanel`:
  Tabs
    TabList
      Tab 0
      Tab 1 (active)
      Tab 2
    TabPanel 0
    TabPanel 1 (corresponds to active tab)
      Children of TabPanel 1
    TabPanel 2

vs.

Example 2, with `forceRenderTabPanel`:
  Tabs
    TabList
      Tab 0
      Tab 1 (active)
      Tab 2
    TabPanel 0 (inactive, but still rendered ("mounted") because of `forceRenderTabPanel`)
      Children of TabPanel 0
    TabPanel 1 (corresponds to active tab)
      Children of TabPanel 1
    TabPanel 2 (inactive, but still rendered ("mounted") because of `forceRenderTabPanel`)
      Children of TabPanel 2

In example 1, when you switch to Tab 0, the contents of TabPanel 1 will be unmounted and that of TabPanel 0 will be mounted. When you switch back to Tab 1, the reverse will happen, and no amount of memoizing the React component in TabPanel 1 will prevent it from being rendered (i.e. the function being executed) again. That is just how React works!

In example 2, the content of all TabPanels will be mounted as soon as the Tabs component is mounted. Great, now you will not refetch when switching tabs! However, since all your TabPanel content now renders (is mounted) immediately, all those components will do their expensive operations (e.g. fetching data). There's a good chance you don't want that either. react-tabs does not include functionality out-of-the-box to deal with this problem.

One way to deal with this is to only mount TabPanel content once, when the tab is first activated. This can be achieved by adding the forceRender prop to a TabPanel only after it is first rendered. There are multiple ways to achieve this, but one would be to use the onSelect callback to keep some state regarding which tabs have already rendered, and apply the forceRender prop to those tabs you want to persist in the DOM once they have rendered. Something like this:

function PostMountPersistedTabs() {
  const [renderedPanels, setRenderedPanels] = useState([0]);

  const onSelect = useCallback((index) => {
    setRenderedPanels((renderedPanels) =>
      renderedPanels.includes(index)
        ? renderedPanels
        : renderedPanels.concat(index)
    )
  }, []);

  return (
    <Tabs onSelect={onSelect}>
      <TabList>
        <Tab>0</Tab>
        <Tab>1</Tab>
        <Tab>2</Tab>
      </TabList>
      <TabPanel forceRender={renderedPanels.includes(0)}>Panel 0</TabPanel>
      <TabPanel forceRender={renderedPanels.includes(1)}>Panel 1</TabPanel>
      <TabPanel forceRender={renderedPanels.includes(2)}>Panel 2</TabPanel>
    </Tabs>
  );
};

Of course this is a very simple example, but the principle stands.

FWIW I think at this point we've had this question come up so many times in various forms that I think it can be argued that react-tabs should provide this functionality itself, as apparently it's confusing to many people. But for that to happen someone has to do the work of defining the feature, getting consensus on the API, and implementing it.

from react-tabs.

joepvl avatar joepvl commented on July 20, 2024

Hi. I'm not sure where you got the idea that memo will have an effect on how/whether inactive tab panels are rendered. If you want them to be rendered, you can pass the forceRenderTabPanel prop to <Tabs>. This is in the README: https://github.com/reactjs/react-tabs#forcerendertabpanel-boolean.

from react-tabs.

ishandutta2007 avatar ishandutta2007 commented on July 20, 2024

@joepvl So you mean react-tabs cache by default if all props are same on next visit ? Well for me it didn't, the code is above , so whats wrong with the above code such that despite props.question being exactly same it's still re-rendering ?
P1QueryTab looks like this:

import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
import 'react-tabs/style/react-tabs.css';
import { memo, useCallback, useState } from 'react'

function P1QueryTab(props: Props) {
    let answer = some_external_api(props.question)
    return (
            <div>{props.question}/></div>
            <div>{answer}/></div>
    )
}

export default P1QueryTab

I don't want to call some_external_api again if the props.question passed to the tab remains same.

from react-tabs.

ishandutta2007 avatar ishandutta2007 commented on July 20, 2024

The data above is over simplified. I posted the same question on stackoverflow with exact data; there folks have blamed the library saying that it doesn't hide the tab by css but removes it totally from the dom tree.

I think your answer is fine if I was only rendering props.question and not answer.
My understanding was memo would prevent external api call if all props are same despite the fact I have in html something that's not a direct prop.

from react-tabs.

ishandutta2007 avatar ishandutta2007 commented on July 20, 2024

I'm going to assume by "next visit" you mean the next time a TabPanel is selected.

Correct

example-1 and example-2 are both hazardous.
I am surprised why example-1 is the default behaviour and not example-3.

from react-tabs.

ishandutta2007 avatar ishandutta2007 commented on July 20, 2024

I'm going to assume by "next visit" you mean the next time a TabPanel is selected.

CorrectπŸ‘

example-1 and example-2 are both hazardous.
I am surprised why example-1 is the default behaviour and not example-3.

Thank you . Great illustration. πŸ‘

from react-tabs.

ishandutta2007 avatar ishandutta2007 commented on July 20, 2024

One doubt I still have, your example-3 will always render it once irrespective of what prop I pass to each TabPanel. right?
Say I start with tab-1 , then I visit tab-2 and then I come back to tab-1 ; this time tab-1 will not rerender. right?
But I may need to re-render if my activities on tab-2 have led to change of props passed to tab-1 on next visit. So the decision is not only based on "if it was rendered earlier or not" but also based on "if it was rendered earlier with exact same props or not". So essentially I will have to maintain the questions for each of the 3 tabs instead of just indices of renderedPanels at the parent level. Dealing with lots of variables and their logic within onSelect makes approach very untidy which is why I was looking for some out of the box memorization based of function arguments. Will get back to you after combining forceRender with memo. Let's see.

from react-tabs.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.