Need help with use-context-selector?
Click the “chat” button below for chat support from the developer who created it, or find similar developers for support.

About the developer

dai-shi
808 Stars 20 Forks MIT License 167 Commits 3 Opened issues

Description

React useContextSelector hook in userland

Services available

!
?

Need anything else?

Contributors list

# 26,791
Redux
reactjs
TypeScr...
hooks-a...
132 commits
# 4,218
GraphQL
repl
React
virtual...
10 commits
# 490,396
CSS
HTML
React
react-h...
1 commit
# 31,428
React
TypeScr...
Shell
vite
1 commit
# 162,337
React
JavaScr...
react-h...
TypeScr...
1 commit
# 146,395
C
Shell
React
react-c...
1 commit

use-context-selector

CI npm size discord

React useContextSelector hook in userland

Introduction

React Context and useContext is often used to avoid prop drilling, however it's known that there's a performance issue. When a context value is changed, all components that useContext will re-render.

To solve this issue, useContextSelector is proposed and later proposed Speculative Mode with context selector support. This library provides the API in userland.

Prior to v1.3, it uses

changedBits=0
feature to stop propagation, v1.3 no longer depends on this undocumented feature.

Install

This package requires some peer dependencies, which you need to install by yourself.

yarn add use-context-selector react scheduler

Notes for library authors:

Please do not forget to keep

"peerDependencies"
and note instructions to let users to install peer dependencies.

Technical memo

To make it work like original React context, it uses useReducer cheat mode intentionally. It also requires

useContextUpdate
to behave better in Concurrent Mode. (You don't need to use it in Legacy Mode.)

Usage

import React, { useState } from 'react';
import ReactDOM from 'react-dom';

import { createContext, useContextSelector } from 'use-context-selector';

const context = createContext(null);

const Counter1 = () => { const count1 = useContextSelector(context, v => v[0].count1); const setState = useContextSelector(context, v => v[1]); const increment = () => setState(s => ({ ...s, count1: s.count1 + 1, })); return (

Count1: {count1} +1 {Math.random()}
); };

const Counter2 = () => { const count2 = useContextSelector(context, v => v[0].count2); const setState = useContextSelector(context, v => v[1]); const increment = () => setState(s => ({ ...s, count2: s.count2 + 1, })); return (

Count2: {count2} +1 {Math.random()}
); };

const StateProvider = ({ children }) => { const [state, setState] = useState({ count1: 0, count2: 0 }); return ( <context.provider value="{[state," setstate> {children} </context.provider> ); };

const App = () => ( );

ReactDOM.render(, document.getElementById('app'));

API

createContext

This creates a special context for

useContextSelector
.

Parameters

  • defaultValue
    Value

Examples

import { createContext } from 'use-context-selector';

const PersonContext = createContext({ firstName: '', familyName: '' });

useContextSelector

This hook returns context selected value by selector.

It will only accept context created by

createContext
. It will trigger re-render if only the selected value is referentially changed.

The selector should return referentially equal result for same input for better performance.

Parameters

  • context
    Context<Value>
  • selector
    function (value: Value): Selected

Examples

import { useContextSelector } from 'use-context-selector';

const firstName = useContextSelector(PersonContext, state => state.firstName);

useContext

This hook returns the entire context value. Use this instead of React.useContext for consistent behavior.

Parameters

  • context
    Context<Value>

Examples

import { useContext } from 'use-context-selector';

const person = useContext(PersonContext);

useContextUpdate

This hook returns an update function that accepts a thunk function

Use this for a function that will change a value in Concurrent Mode. Otherwise, there's no need to use this hook.

Parameters

  • context
    Context<Value>

Examples

import { useContextUpdate } from 'use-context-selector';

const update = useContextUpdate(); update(() => setState(...));

BridgeProvider

This is a Provider component for bridging multiple react roots

Type: FC<{context: Context<any>, value: any}>

Parameters

  • $0
    Object
    • $0.context

    • $0.value

    • $0.children

Examples

const valueToBridge = useBridgeValue(PersonContext);
return (
  
    
      {children}
    
  
);

useBridgeValue

This hook return a value for BridgeProvider

Parameters

  • context
    Context<any>

Limitations

  • In order to stop propagation,
    children
    of a context provider has to be either created outside of the provider or memoized with
    React.memo
    .
  • Provider trigger re-renders only if the context value is referentially changed.
  • Neither context consumers or class components are supported.
  • The stale props issue can't be solved in userland.
  • Tearing is only avoided if all consumers get data using
    useContextSelector
    . If you use both props and
    use-context-selector
    to pass the same data, they may provide inconsistence data for a brief moment. (
    02_tearing_spec
    fails)

Examples

The examples folder contains working examples. You can run one of them with

PORT=8080 yarn run examples:01_minimal

and open http://localhost:8080 in your web browser.

You can also try them in codesandbox.io: 01 02

Projects that use use-context-selector

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.