npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

react-context-toolkit

v1.0.7

Published

Toolkit for React Context API heavily inspired by @reduxjs/toolkit and react-redux

Downloads

314

Readme

react-context-toolkit

Toolkit for React Context API - heavily inspired by @reduxjs/toolkit and react-redux. Written in TypeScript.

  • It uses the React Context API instead of Redux for managing state under the hood.
  • Depends on use-context-selector to prevent unneccesary rerenders. (https://github.com/reactjs/rfcs/pull/119)

Motivation

I really like the combination of react-redux and @reduxjs/toolkit. React-Redux won't work for me due to this issue:

  • https://github.com/visgl/deck.gl/issues/4550

The context API in React doesn't suffer from the same problem, so I decided to make this feel more like I'm using Redux.

API

createStore([...slices]):

const {
  StateProvider,
  useSelector,
  useDispatch,
  Store,
  initialState,
  rootReducer,
} = createStore([
  slice1,
  slice2,
  // ...
])

| returned object | description | | ---------------------------- | ----------------------------------------------------------------------------------------------------- | | StateProvider | The context provider (React Element) that provides the store to all its children | | useSelector(selector) | Hook that selects from the global store (and only rerenders if the selected state has changed) | | useDispatch() | Hook that returns a dispatch function, just like the one in React-Redux | | Store | In case you need direct access to the React Context object | | initialState | The complete initial state. The slice names are keys, under which each slice has its own initialState | | rootReducer(state, action) | The reducer that takes in the combined state, an action, and produces a new combined state |

createSlice(): This is exported directly from @reduxjs/toolkit. API DOCS HERE

Getting Started

Installation

# Using npm
npm install --save react-context-toolkit

# using yarn
yarn add react-context-toolkit

Example

Also, check out the test folder for another example.

Wrapping the application in a provider

// ./src/index.tsx

import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import { StateProvider } from './app/store'

// Wrap your app in the state provider like this:
ReactDOM.render(
  <React.StrictMode>
    <StateProvider>
      <App />
    </StateProvider>
  </React.StrictMode>,
  document.getElementById('root')
)

The App component

Notice that it doesn't need to know anything about the store

// src/App.tsx

import React from 'react'
import Component1 from '../features/component1/Component1'
import Component2 from '../features/component2/Component2'
import Component3 from '../features/component3/Component3'

// Note that the App component doesn't need to know anything about the store!
export default function App () {
  return (
    <>
      <Component1 />
      <Component2 />
      <Component3 />
    </>
  )
}

Creating the store

// src/app/store.ts

import { createStore } from 'react-context-toolkit'
import componentSlice1 from '../features/component1/componentSlice1'
import componentSlice2 from '../features/component2/componentSlice2'
import componentSlice3 from '../features/component3/componentSlice3'

export const {
  useSelector,
  useDispatch,
  StateProvider,
  initialState,
} = createStore([componentSlice1, componentSlice2, componentSlice3])

// In case you need direct access to the type of the combined state
export type RootState = typeof initialState

Creating a slice (similar to how it is done in @reduxjs/toolkit)

// src/features/component1/componentSlice1.ts

import { createSlice, PayloadAction } from 'react-context-toolkit'
// ^ You can also import these from '@reduxjs/toolkit'
import { RootState } from '../../app/store'

const slice = createSlice({
  // This name becomes the key in the global state
  name: 'component1',
  initialState: {
    value: 1,
  },
  reducers: {
    // uses immer reducers to allow mutations on an intermediate draft state
    increment (state) {
      state.value++
    },
    incrementBy (state, action: PayloadAction<number>) {
      state.value += action.payload
    },
  },
})
export const { increment, incrementBy } = slice.actions
export const selectValue = (state: RootState) => state[slice.name].value

How state can be used and updated from a component

// src/features/component1/Component1.tsx

import React from 'react'
import { useSelector, useDispatch } from '../../app/store'
import { increment, incrementBy, selectValue } from './componentSlice1'

export default function Component1 () {
  const value = useSelector(selectValue)
  const dispatch = useDispatch()
  return (
    <button onClick={() => dispatch(increment())}>
      I have been clicked {value} times!
    </button>
  )
}

For more examples, see the test folder on GitHub

Roadmap

  • Ability to add your own middleware/docs
  • Redux-thunk support/docs
  • Redux-saga support/docs
  • Persistence support/docs (using localStorage) -> requiring serializable state
  • Reselect support/docs (for computationally intensive selects)