DEV Community

Antonio Pangallo
Antonio Pangallo

Posted on

Redhooks: predictable state container for React applications.

Redhooks Repository

WHAT IS REDHOOKS?

Redhooks is a tiny library for holding a predictable state container within your React applications. Inspired by Reduxjs, it reimplements Redux’s API using the experimental Hooks API and the Context API. It supports the use of middleware like redux-thunk, redux-saga or your custom middleware conforming to the middleware's API.

Let's start to write our first simple application by using redhooks.

Reducer

A reducer is a pure function that takes the previous state and an action which is a plain object, and returns the next state.

./reducer.js

import { combineReducers } from "redhooks";

const greeting = (state = "good morning", { type, payload }) => {
  switch (type) {
    case "GREET":
      state = payload;
      return state;
    default:
      return state;
  }
};

const counter = (state = 0, { type, payload }) => {
  switch (type) {
    case "INCREMENT":
      return state + 1;
    case "DECREMENT":
      return state - 1;
    default:
      return state;
  }
};

const rootReducer = combineReducers({ greeting, counter });
export default rootReducer;
Enter fullscreen mode Exit fullscreen mode

Store

A store holds the whole state tree of your application. The state within a store is read only, the only way to change the state is to dispatch an action. To create a store we need to pass our root reducing function to createStore(reducer, [opts]).

./store.js

import { createStore } from "redhooks";
import rootReducer from "./reducers";

const opts = {
  preloadedState: { counter: 1 },
  initialAction: { type: "INCREMENT" }
};
const store = createStore(rootReducer, opts);

export default store;
Enter fullscreen mode Exit fullscreen mode

Counter - Function Component

Within function components in order to access the store we can use the useStore() redhooks API. This returns an object with props that are the state object and the dispatch function.

./components/Counter.js

import React from "react";
import { useStore } from "redhooks";
const Counter = () => {
  const { state, dispatch } = useStore();
  const { counter } = state;
  return (
    <div>
      <h1>{counter}</h1>
      <button onClick={() => dispatch({ type: "INCREMENT" })}> + </button>
      <button onClick={() => dispatch({ type: "DECREMENT" })}> - </button>
    </div>
  );
};
export default Counter;
Enter fullscreen mode Exit fullscreen mode

Greeter - Class Component

Within a class component due to the fact that React Hooks are not allowed, we need to use the connect redhooks API which connects either Class or Function Components to the redhooks store

./components/Greeter.js

import React, { Component } from "react";
import { connect } from "redhooks";
class Greeter extends Component {
  render() {
    const { greeting, dispatch } = this.props;
    return (
      <div>
        <h1>{greeting}</h1>
        <button onClick={() => dispatch({ type: "GREET", payload: "HELLO" })}>
          say hello
        </button>
        <button onClick={() => dispatch({ type: "GREET", payload: "GOODBYE" })}>
          say goodbye
        </button>
      </div>
    );
  }
}
const mapStateToProps = state => ({ greeting: state.greeting });
export default connect(mapStateToProps)(Greeter);
Enter fullscreen mode Exit fullscreen mode

Using the mapStateToProps method we can subscribe any components to the redhooks store. Any time the store is updated, mapStateToProps will be called and it's results, which must be a plain object, will be merged into your component's props. In the example above two props are injected, greeting and dispatch.

We could have avoid to use the connect for the Greeter Class Component. It was only used for showing how it works. You can get more details on why and when it should be used at redhooks docs

Now let's put all together and render our tiny application.

App Component

./components/App.js

import React from "react";
import Counter from "./Counter";
import Greeter from "./Greeter";

const App = () => (
  <div>
    <Counter />
    <Greeter />
  </div>
);

export default App;
Enter fullscreen mode Exit fullscreen mode

Render the application

./index.js

import React from "react";
import { render } from "react-dom";
import Provider from "redhooks";

import store from "./store";
import App from "./components/App";

render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);
Enter fullscreen mode Exit fullscreen mode

We are done! A live codesandbox example for you to play with!

Other Sandbox Examples

Following few open source projects implemented with redux have been migrated to redhooks:

Shopping Cart: CodeSandbox
TodoMVC: CodeSandbox
Tree-View: CodeSandbox
Saga-Middleware: CodeSandbox

Conclusion

Hope you enjoyed reading this post. If you did, please checking out the redhooks repo, or even better contribute to redhooks. Thanks.

GitHub logo iusehooks / redhooks

Predictable state container for React apps written using Hooks

Redhooks Logo

Redhooks is a tiny React utility library for holding a predictable state container in your React apps Inspired by Redux, it reimplements the redux paradigm of state-management by using React's new Hooks and Context API, which have been officially released by the React team.

Build Status Package size Coverage Status License Tweet

Installation

npm install --save redhooks
Enter fullscreen mode Exit fullscreen mode

Motivation

In the Reactjs docs a nice paragraph titled useYourImagination() suggests to think of different possible usages of functionality Hooks provide, which is essentially what Redhooks tries to do This package does not use any third party library, being only dependent upon the Hooks and the Context API. You do not need to install react-redux to connect your components to the store because you can have access to it directly from any of your function components by utilizing the useStore Redhooks API.…

Top comments (0)