1.0.10 • Published 4 years ago

real-simple-context v1.0.10

Weekly downloads
-
License
MIT
Repository
github
Last release
4 years ago

Real Simple Context

  • Quick and easy reducer-based context setup
  • Isolate component updates to specific slices of state with selectors (uses use-context-selection)

Install

yarn add real-simple-context

Table of Contents

  1. Example
  2. createReducerContext
  3. referenceContext param
  4. equalityTest param
  5. Reducer and initialState with vanilla JS
  6. Typescript

Example

CODESANDBOX

context.js (createReducerContext)

import { createReducerContext } from 'real-simple-context';

const initialState = { counter: 0, totalIncrements: 0, totalDecrements: 0 };

const reducer = (state = initialState, action) => {
  switch (action.type) {
    case 'SET_COUNTER_VALUE': {
      return {
        ...state,
        counter: action.value,
      };
    }
    case 'INCREMENT': {
      return {
        ...state,
        counter: state.counter + 1,
        totalIncrements: state.totalIncrements + 1,
      };
    }
    case 'DECREMENT': {
      return {
        ...state,
        counter: state.counter - 1,
        totalDecrements: state.totalDecrements + 1,
      };
    }
    default: {
      return state;
    }
  }
};

const setCounterValue = (dispatch) => (value) => {
  dispatch({
    type: 'SET_COUNTER_VALUE',
    value,
  });
};

const increment = (dispatch) => () => {
  dispatch({
    type: 'INCREMENT',
  });
};

const decrement = (dispatch) => () => {
  dispatch({
    type: 'DECREMENT',
  });
};

const actions = { setCounterValue, increment, decrement };

export const { Provider, useSelector, useActions } = createReducerContext(
  reducer,
  actions,
  initialState
);

index.js (Provider)

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from './context';

ReactDOM.render(
  <Provider>
    <App />
  </Provider>,
  document.getElementById('root')
);

Display.js (useSelector)

import React from 'react';
import { useSelector } from './context';

const Display = ({ stateKey }) => {
  const value = useSelector((state) => state[stateKey]);

  return (
    <div className='display'>
      {stateKey}: {value}
    </div>
  );
};

export default Display;

Buttons.js (useActions)

import React from 'react';
import { useActions } from './context';

const Buttons = () => {
  const { setCounterValue, increment, decrement } = useActions();

  return (
    <div>
      <button type='button' onClick={decrement}>
        Decrement
      </button>
      <button type='button' onClick={increment}>
        Increment
      </button>
      <button
        type='button'
        onClick={() => setCounterValue(Math.floor(Math.random(0, 1) * 100))}
      >
        Randomize
      </button>
    </div>
  );
};

export default Buttons;

App.js

import React from 'react';
import Display from './Display';
import Buttons from './Buttons';
import './App.css';

function App() {
  return (
    <div className='App'>
      <div className='container'>
        <Display stateKey='counter' />
        <Display stateKey='totalIncrements' />
        <Display stateKey='totalDecrements' />
      </div>
      <Buttons />
    </div>
  );
}

export default App;

createReducerContext

ParamTypeDescriptionOptional / Required
reducerFunctionReducer for ContextRequired
actionsObjectMap of actionsRequired
initialStateObjectInitial state for reducerRequired
referenceContextBooleanIf true, provides a Context with a reference value (object) docsOptional
equalityTestFunctionFunction to compare previous and current state docsOptional
  • Return Value: Object - { Provider, useSelector, useActions }

Provider

ParamTypeDescriptionOptional / Required
initStateObjectOverwrites initialState set through createReducerContextOptional

Example

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from './context';

ReactDOM.render(
  <Provider initState={{ counter: 5 }}>
    <App />
  </Provider>,
  document.getElementById('root')
);

useSelector

Uses use-context-selection

ParamTypeDescriptionOptional / Required
selectorFunctionSelector function to retrieve slice of stateRequired
  • Return Value: any

Example

const counter = useSelector((state) => state.counter);
const multiple = useSelector((state) => ({
  counter: state.counter,
  totalIncrements: state.totalIncrements,
}));

useActions

  • Return Value: Object

Example

const { increment } = useActions();

// ...

<button onClick={increment}>Increment</button>;

referenceContext param

If true, provides a Context with a reference value (object)

context.js

import {createReducerContext} from 'real-simple-context';

const initialState = { ... };

const reducer = (state = initialState, action) => {
    // .....
}

const actions = { ... };

const { Provider, useSelector, useActions, useReference } = createReducerContext(
    reducer,
    actions,
    initialState,
    true
);

AppComponent.js

import React from 'react';
import { useReference } from './context';

const AppComponent = (props) => {
  const reference = useReference();

  React.useEffect(() => {
    reference.current.AppConfig = props.AppConfig;
  }, []);

  // ....
};

equalityTest param

Function to compare previous and current state

context.js

import isEqual from 'lodash/isEqual';
import {createReducerContext} from 'real-simple-context';

const initialState = { ... };

const reducer = (state = initialState, action) => {
    // .....
}

const actions = { ... };

const { Provider, useSelector, useActions } = createReducerContext(
    reducer,
    actions,
    initialState,
    false,
    isEqual //will do a recursive equality check
);

Reducer and initialState with vanilla JS

When creating the reducer in normal JS, it's important to set the default value of state to initialState:

import {createReducerContext} from 'real-simple-context';

const initialState = { ... };

const reducer = (state = initialState, action) => {
    .....
}

If you don't do this, the property typing won't be correct on the selector state object when using useSelector.

Typescript

real-simple-context exports two types for convenience when setting up a reducer context in typescript: Reducer and DispatchAction

import {createReducerContext, Reducer, DispatchAction} from 'real-simple-context';

const initialState = {...};

const reducer:Reducer<typeof initialState> = (state, action) => {
    ....
}

// ....


const someAction = (dispatch:DispatchAction) => (someString:string) => {
    dispatch({
        type:'SOME_ACTION',
        someString
    })
}

....
1.0.10

4 years ago

1.0.9

5 years ago

1.0.8

5 years ago

1.0.7

5 years ago

1.0.6

5 years ago

1.0.5

5 years ago

1.0.4

5 years ago

1.0.3

5 years ago

1.0.2

5 years ago

1.0.1

5 years ago

1.0.0

5 years ago