1.0.3 • Published 5 years ago

react-dumb-store v1.0.3

Weekly downloads
2
License
MIT
Repository
github
Last release
5 years ago

react-dumb-store

A small isomorphic state container for React that you can understand in 2 minutes.

Features

Motivation

All these state containers out there are such overkill. You need to learn all this termonology before you can even get started: actions, reducers, action creators... there's so much boilerplate (looking at you, Redux).

Can't we make something better simpler?

Note: This package doesn't include any functionality regarding middleware, time-traveling devtools, or other features that you might find in other state container packages. It is meant only to persist values universally in a global store, and to easily update those values, and nothing more (hence "dumb").

Usage

0. Install

yarn add react-dumb-store

1. Provide

We'll use Next.js's convention of _app.js to illustrate wrapping your app in the StoreProvider component. Most importantly, you need to initialize the store in state, and pass a function that updates state to store.observe (either in your render function, or in componentDidMount).

// _app.js
import React from 'react'
import App, { Container } from 'next/app'
import store, { StoreProvider } from 'react-dumb-store'

export default class MyApp extends App {
  static async getInitialProps({ Component, ctx }) {
    const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {}

    // example server-side fetch that occurs once during client-side navigation
    if (!store.get('name')) {
      const res = await fetch('https://api.npms.io/v2/search/suggestions?q=react')
      store.set({ name: res.json()[0].package.name })
    }

    return { pageProps }
  }

  state = {
    // initialize the store in state
    store: store.get(),
  }

  componentDidMount() {
    // sets a function to run after `store.set()` is called
    store.observe(this.updateStore)
  }

  updateStore = () => {
    this.setState({ store: store.get() })
  }

  render() {
    const { Component, pageProps } = this.props
    
    return (
      <Container>
        <StoreProvider value={this.state.store}>
          <Component {...pageProps} />
        </StoreProvider>
      </Container>
    )
  }
}

2. Consume

Wrap the StoreConsumer component around wherever you'd like to use a value from the store.

// DeeplyNestedChildComponent.js
import React from 'react'
import store, { StoreConsumer } from 'react-dumb-store'

const changeName = () => {
  store.set({
    name: 'Quincy Jones',
  })
}

const DeeplyNestedChildComponent = () => (
  <StoreConsumer>
    {({ name }) => (
      <p>Hi {name}!</p>
      <button onClick={changeName}>Change name</button>
    )}
  </StoreConsumer>
)

export default DeeplyNestedChildComponent

3. Hydrate (optional)

If you're rendering your markup server-side (like with Next.js), you'll need to hydrate your client so that you avoid a duplicate fetch and that the store can get passed from the server to client. Here we'll edit _document.js:

// _document.js
import React from 'react'
import Document, { Main, NextScript } from 'next/document'
import { hydrateStore } from 'react-dumb-store'

export default class extends Document {
  static getInitialProps({ renderPage }) {
    const page = renderPage()
    return { ...page }
  }

  render() {
    return (
      <html>
        <body>
          <Main />
          {hydrateStore()}
          <NextScript />
        </body>
      </html>
    )
  }
}

Behind the scenes

Under the hood, this relies on React Context. You must use React 16.3 or higher in order to use react-dumb-store.