Skip to content

Instantly share code, notes, and snippets.

@pie6k
Last active October 28, 2021 18:57
Show Gist options
  • Save pie6k/20beb73aaceac2bb9d02e929514da2f9 to your computer and use it in GitHub Desktop.
Save pie6k/20beb73aaceac2bb9d02e929514da2f9 to your computer and use it in GitHub Desktop.
<Freeze /> React Component
/**
* Goal:
*
* Being able to freeze some part of react tree and stop all updates from 'react word' for part of the tree for some period of time.
* It would prevent ui from updating in any way (props change, state change, hooks change etc)
*
* Use case:
*
* Let's say there is tab based react-native app.
* All of the screens are rendered all the time, and by using some store (redux etc)
* changes made in one tab might get reflected in another tab.
*
* Inactive tab might also have some inner updates (like clock components etc)
*
* We don't really want that as we dont even see inactive tab.
*
* But because of complexity, it might be hard to disable all updates easily eg.
* - it might be listening to relay/apollo updates
* - it might be listening to redux or other store
* - it might just have some inner timers or state that updates frequently (eg. <CountDown /> component we cannot manually stop)
* - etc
*
* Technically it would be possible to create some sort of context near the top of the tree like isFocusedContext,
* but again, it would require all different kinds of components to properly enable/disable updates using it
*
*
* API
*
* There would be special component called `Freeze`, and everything inside it would ignore
* every update in react word (both props and state/hooks based)
*
* ```
* <Freeze isEnabled>
* <Clock />
* </Freeze>
* ```
*
* Even if there would be some component like `<CountDown />` inside <Freeze>, that has some inner state that is updating every second, those updates would be ignored by react and not reflected in the UI
* until `isEnabled` prop becomes false.
*
* Technically, those components would update their states (eg. <CountDown /> also has `ticksCount` that increases every second).
* This `tickCount` would increase normally, but updates would not be rendered. However, when we'd `unfreeze` it, we would see accurate state
*
* When updates are enabled again, entire tree would be re-rendered and become 'live' again
*
*
*/
@AlexeiDarmin
Copy link

Since this is the first Google result, lemme slap on some code here that worked for my version of this problem.

This can be partially accomplished by implementing shouldComponentUpdate at the desired root node of the 'freeze'. Children components that rely on the same data must retrieve it as props from the frozen parent (as opposed to react context, redux, or side-effect based data-providers).

This allows control over many conditional frozen and unfrozen states.

How to implement shouldComponentUpdate for React hooks to disable component rerenders can be found here: https://stackoverflow.com/questions/54551949/react-hooks-how-do-i-implement-shouldcomponentupdate

Caveat:

  • Will need to apply freezing logic to each layer of component that retrieves data from any source other than the parent frozen component.

For example: The below code freeze's a component from updating so long as criticalID is missing from props.

const SomeComponent = React.memo(SomeComponentBase, (props, nextProps) => {
  if (!nextProps.criticalID) {
    return true
  }
}

@reme3d2y
Copy link

const Freezer = React.memo<{ children: ReactNode; freeze: boolean }>(
    ({ children }) => <React.Fragment>{ children }</React.Fragment>,
    (_, nextProps) => nextProps.freeze,
);

// usage
<Freezer freeze={ freeze}>
    <div>
       The part of the component that should not change when freeze flag is true
    </div>
</Freezer>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment