Skip to content

Commit

Permalink
Merge pull request #77 from shipt/development
Browse files Browse the repository at this point in the history
Release 1.2.0
  • Loading branch information
chaceburnette authored Aug 18, 2021
2 parents ff817c9 + 3a0a197 commit e2ad358
Show file tree
Hide file tree
Showing 16 changed files with 123 additions and 65 deletions.
2 changes: 1 addition & 1 deletion .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
@@ -1 +1 @@
* @chaceburnette @lein-haz @joshuakg @jkhusanov @divijadesai @taylorcore @MarquessV @TomMahle
* @chaceburnette @lein-haz @joshuakg @jkhusanov @divijadesai @taylorcore @MarquessV @TomMahle @ChiefoftheOwls
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## v1.2.0

* BREAKING CHANGE - Modified the return format for `setupStore` to be a single object instead of an array of parts
* `usePersistedState` - the set state function now supports the functional state update syntax

## v1.1.1

* Minor dependency updates
Expand All @@ -15,7 +20,7 @@
## v1.0.1

* Cleaning up some unused files
* Adding better error messages for usePersistedState and StoreProvider
* Adding better error messages for `usePersistedState` and `StoreProvider`
* README updates and tweaks

## v1.0.0
Expand Down
4 changes: 2 additions & 2 deletions examples/counter-react/src/App.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { StoreProvider, configureUsePersistedState } from '@shipt/osmosis';
import { CounterWrapper, CounterWithReducerWrapper } from './store';
import { CounterStore, CounterWithReducerStore } from './store';

import Counter from './counter';
import PersistedCounter from './persistedCounter.js';
Expand All @@ -20,4 +20,4 @@ const App = () => {
);
};

export default StoreProvider([CounterWrapper, CounterWithReducerWrapper], App);
export default StoreProvider([CounterStore.Provider, CounterWithReducerStore.Provider], App);
12 changes: 6 additions & 6 deletions examples/counter-react/src/__tests__/counter.spec.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import React from 'react';
import Counter from '../counter';
import { CounterContext } from '../store';
import { CounterStore } from '../store';
import { render, fireEvent } from '@testing-library/react';

describe('Counter', () => {
const CounterStore = {
const counterStore = {
state: {
count: 0
},
incrementCount: jest.fn(),
decrementCount: jest.fn()
};
let ContextComponent = () => (
<CounterContext.Provider value={[CounterStore]}>
<CounterStore.Context.Provider value={[counterStore]}>
<Counter />
</CounterContext.Provider>
</CounterStore.Context.Provider>
);
it('renders default', async () => {
let wrapper = await render(<ContextComponent />);
Expand All @@ -23,11 +23,11 @@ describe('Counter', () => {
it('tests increment button', async () => {
let wrapper = await render(<ContextComponent />);
fireEvent.click(wrapper.getByTestId('increment'));
expect(CounterStore.incrementCount).toHaveBeenCalled();
expect(counterStore.incrementCount).toHaveBeenCalled();
});
it('tests decrement button', async () => {
let wrapper = await render(<ContextComponent />);
fireEvent.click(wrapper.getByTestId('decrement'));
expect(CounterStore.decrementCount).toHaveBeenCalled();
expect(counterStore.decrementCount).toHaveBeenCalled();
});
});
4 changes: 2 additions & 2 deletions examples/counter-react/src/counter.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import { CounterContext } from './store';
import { CounterStore } from './store';

const Counter = () => {
const [counterContext] = useContext(CounterContext);
const [counterContext] = useContext(CounterStore.Context);
let { count } = counterContext.state;

return (
Expand Down
6 changes: 3 additions & 3 deletions examples/counter-react/src/dispatchCounter.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import { CounterWithReducerContext } from './store';
import { CounterWithReducerStore } from './store';

const PersistedCounter = () => {
const [counterContext] = useContext(CounterWithReducerContext);
const [counterContext] = useContext(CounterWithReducerStore.Context);
let { dispatch, counterState: { count }} = counterContext;

return (
Expand All @@ -18,4 +18,4 @@ const PersistedCounter = () => {
);
};

export default PersistedCounter;
export default PersistedCounter;
4 changes: 2 additions & 2 deletions examples/counter-react/src/persistedCounter.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { useContext } from 'react';
import { CounterContext } from './store';
import { CounterStore } from './store';

const PersistedCounter = () => {
const [counterContext] = useContext(CounterContext);
const [counterContext] = useContext(CounterStore.Context);
let { persistedCount } = counterContext.state;

return (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import React, { useContext } from 'react';
import { CounterContext, CounterWrapper} from '../counter.store';
import CounterStore from '../counter.store';
import { render } from '@testing-library/react';
import { act } from 'react-dom/test-utils';

describe('CounterStore', () => {
let store;
const renderStore = () => {
let Prep = CounterWrapper(() => {
store = useContext(CounterContext)[0];
let Prep = CounterStore.Provider(() => {
store = useContext(CounterStore.Context)[0];
return null;
});
render(<Prep />);
Expand Down
8 changes: 5 additions & 3 deletions examples/counter-react/src/store/counter.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ const useCounterContainer = () => {

const decrementCount = () => setCount(count - 1);

const incrementPersistedCount = () => setPersistedCount(persistedCount + 1);
// showing supporting functional state updates
const incrementPersistedCount = () => setPersistedCount(currentCount => currentCount + 1);

// showing supporting non-functional state updates
const decrementPersistedCount = () => setPersistedCount(persistedCount - 1);

return {
Expand All @@ -25,6 +27,6 @@ const useCounterContainer = () => {
};
};

let [CounterContext, CounterWrapper, counterRef] = setupStore(useCounterContainer);
let CounterStore = setupStore(useCounterContainer);

export { CounterContext, CounterWrapper, counterRef };
export default CounterStore ;
4 changes: 2 additions & 2 deletions examples/counter-react/src/store/counterWithReducer.store.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,6 @@ const useCounterWithReducerStore = () => {
};
};

let [CounterWithReducerContext, CounterWithReducerWrapper, counterWithReducerRef] = setupStore(useCounterWithReducerStore);
let CounterWithReducerStore = setupStore(useCounterWithReducerStore);

export { CounterWithReducerContext, CounterWithReducerWrapper, counterWithReducerRef};
export default CounterWithReducerStore;
4 changes: 2 additions & 2 deletions examples/counter-react/src/store/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
export { CounterContext, CounterWrapper, counterRef } from './counter.store';
export { CounterWithReducerContext, CounterWithReducerWrapper, counterWithReducerRef} from './counterWithReducer.store.js';
export { default as CounterStore } from './counter.store';
export { default as CounterWithReducerStore } from './counterWithReducer.store.js';
20 changes: 10 additions & 10 deletions examples/counter-react/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1502,7 +1502,7 @@
integrity sha512-DetpxZw1fzPD5xUBrIAoplLChO2VB8DlL5Gg+I1IR9b2wPqYIca2WSUxL5g1vLeR4MsQq1NeWriXAVffV+U1Fw==

"@shipt/osmosis@../../osmosis":
version "1.1.0"
version "1.1.1"

"@sinonjs/commons@^1.7.0":
version "1.8.2"
Expand Down Expand Up @@ -8047,9 +8047,9 @@ path-key@^3.0.0, path-key@^3.1.0:
integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==

path-parse@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
version "1.0.7"
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==

[email protected]:
version "0.1.7"
Expand Down Expand Up @@ -10494,9 +10494,9 @@ tapable@^1.0.0, tapable@^1.1.3:
integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==

tar@^6.0.2:
version "6.1.0"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.0.tgz#d1724e9bcc04b977b18d5c573b333a2207229a83"
integrity sha512-DUCttfhsnLCjwoDoFcI+B2iJgYa93vBnDUATYEeRx6sntCTdN01VnqsIuTlALXla/LWooNg0yEGeB+Y8WdFxGA==
version "6.1.5"
resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.5.tgz#6e25bee1cfda94317aedc3f5d49290ae68361d73"
integrity sha512-FiK6MQyyaqd5vHuUjbg/NpO8BuEGeSXcmlH7Pt/JkugWS8s0w8nKybWjHDJiwzCAIKZ66uof4ghm4tBADjcqRA==
dependencies:
chownr "^2.0.0"
fs-minipass "^2.0.0"
Expand Down Expand Up @@ -10952,9 +10952,9 @@ [email protected]:
schema-utils "^3.0.0"

url-parse@^1.4.3, url-parse@^1.4.7:
version "1.5.1"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.1.tgz#d5fa9890af8a5e1f274a2c98376510f6425f6e3b"
integrity sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==
version "1.5.3"
resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862"
integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==
dependencies:
querystringify "^2.1.1"
requires-port "^1.0.0"
Expand Down
30 changes: 14 additions & 16 deletions osmosis/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ import { setupStore } from '@shipt/osmosis';

The `setupStore` function takes in an argument that is just a custom hook. The custom hook will return a single object that represents a slice of state and any functions needed to operate on that state.

`setupStore` returns three variables
`setupStore` returns one variable with 2 properties: `Context` and `Provider`

```js
let [storeContext, wrapperFunction, storeRef] = setupStore(useStateStore);
let store = setupStore(useStateStore);
```

- `storeContext` is a React context variable that gives you access to the state and functions of your store
- `wrapperFunction` is simply a higher-order component used to provide the store to the app and should be used to wrap the top-level component in the app
- `storeRef` is an object that gives you access to state variables and functions without causing re-renders when changes occur
- `store` - a ref to the store object returned from the supplied custom hook
- `store.Context` - a React context variable that gives you access to the state and functions of your store
- `store.Provider` - a higher-order component used to provide the store to the app

To connect the state throughout your app you have to import the `StoreProvider` function which is simply a utility for combining several `wrapperFunction`'s into a single higher order component.

Expand Down Expand Up @@ -75,27 +75,25 @@ const useCounterStore = () => {
};
};

let [CounterContext, wrapCounter, counterRef] = setupStore(useCounterStore);
let CounterStore = setupStore(useCounterStore);

export { CounterContext, wrapCounter };

export default counterRef;
export default CounterStore;
```

```jsx
//counter.js
import React, { useContext } from 'react';
import { CounterContext } from './counter.store';
import { CounterStore } from './counter.store';

export default () => {
const [counterContext] = useContext(CounterContext);
let { count } = counterContext.state;
const [counterStore] = useContext(CounterStore.Context);
let { count } = counterStore.state;

return (
<div>
<p>{count}</p>
<button onClick={counterContext.increment}>+</button>
<button onClick={counterContext.decrement}>-</button>
<button onClick={counterStore.increment}>+</button>
<button onClick={counterStore.decrement}>-</button>
</div>
);
};
Expand All @@ -104,10 +102,10 @@ export default () => {
```jsx
//index.js Root Component
import { StoreProvider } from '@shipt/osmosis';
import { wrapCounter } from './counter.store';
import { CounterStore } from './counter.store';
import Counter from './counter';

export default StoreProvider([wrapCounter], Counter);
export default StoreProvider([CounterStore.Provider], Counter);
```

## State Persistence with usePersistedState
Expand Down
2 changes: 1 addition & 1 deletion osmosis/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@shipt/osmosis",
"version": "1.1.1",
"version": "1.2.0",
"description": "A lightweight state management library for React and React Native",
"keywords": [
"react",
Expand Down
53 changes: 48 additions & 5 deletions osmosis/src/setupStore.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,50 @@
import React, { createContext } from 'react';

const _defaultConfig = { proxyEnabled: false };

/**
* @callback useCustomHook
* @returns {Object}
*/

/**
* @typedef SetupStoreConfig
* @type {Object}
* @property {boolean} proxyEnabled - Determines if the store setup should use proxies internally for the store ref, only if proxies are supported
*/

/**
* @typedef Store
* @type {Object}
* @property {Object} Context - The React Context for the store
* @property {Object} Provider - The higher order component provider for the store
*/

/**
* @param {useCustomHook} useCustomHook
* @returns {Object[]}
* @param {SetupStoreConfig} [config = { proxyEnabled: false }] - The setup store config
* @returns {Store}
*/
const setupStore = useCustomHook => {
const setupStore = (useCustomHook, config = _defaultConfig) => {
const StoreContext = createContext();
// If proxy is not supported
let storeRef = { state: {} };

// If proxy is supported
let storeProxy;
let storeProxyObject = { ref: { state: {} } };

const withStoreContext = WrappedComponent => props => {
let store = useCustomHook();
for (let key in store) {
storeRef[key] = store[key];
if (!!store.Context) throw new Error("'Context' property is protected and cannot exist on a store object");
if (!!store.Provider) throw new Error("'Provider' property is protected and cannot exist on a store object");

if (storeProxy) {
storeProxyObject.ref = store;
} else {
for (let key in store) {
storeRef[key] = store[key];
}
}

return (
Expand All @@ -26,7 +54,22 @@ const setupStore = useCustomHook => {
);
};

return [StoreContext, withStoreContext, storeRef];
if (!!Proxy && config.proxyEnabled) {
storeProxy = new Proxy(storeProxyObject, {
get: (target, property) => {
if (property === 'Context') return StoreContext;
if (property === 'Provider') return withStoreContext;
return target.ref[property];
},
set: (target, property, value) => (target.ref[property] = value)
});
} else {
storeRef.Context = StoreContext;
storeRef.Provider = withStoreContext;
}


return storeProxy || storeRef;
};

export { setupStore };
Loading

0 comments on commit e2ad358

Please sign in to comment.