diff --git a/packages/fluxible-addons-react/src/index.js b/packages/fluxible-addons-react/src/index.js index 79143eb4..f4360b19 100644 --- a/packages/fluxible-addons-react/src/index.js +++ b/packages/fluxible-addons-react/src/index.js @@ -11,3 +11,4 @@ export { default as createElementWithContext } from './createElementWithContext' export { default as provideContext } from './provideContext'; export { default as useFluxible } from './useFluxible'; export { default as withFluxible } from './withFluxible'; +export { default as useStore } from './useStore'; diff --git a/packages/fluxible-addons-react/src/useStore.js b/packages/fluxible-addons-react/src/useStore.js new file mode 100644 index 00000000..d257b528 --- /dev/null +++ b/packages/fluxible-addons-react/src/useStore.js @@ -0,0 +1,36 @@ +import {useEffect, useState} from 'react'; +import useFluxible from './useFluxible' + +/** + * React hook that returns a state from Fluxible store. + * TODO: this is a draft for an ongoing discussion in #733 + * + * Example: + * + * const FooComponent = () => { + * const getStateFromStore = store => store.getFoo(); + * const foo = useStore('FooStore', getStateFromStore); + * return

; + * }; + * + * @function useFluxible + * @returns {object} - a state from Fluxible store + */ +const useStore = (storeName, getStateFromStore) => { + const { getStore } = useFluxible(); + const store = getStore(storeName); + const [state, setState] = useState(getStateFromStore(store)); + + function updateState() { + setState(getStateFromStore(store)); + } + + useEffect(() => { + store.on('change', updateState); + return () => store.removeListener('change', updateState); + }, [store, updateState]); + + return state; +} + +export default useStore; diff --git a/packages/fluxible-addons-react/tests/unit/lib/useStore.js b/packages/fluxible-addons-react/tests/unit/lib/useStore.js new file mode 100644 index 00000000..9ca2bb52 --- /dev/null +++ b/packages/fluxible-addons-react/tests/unit/lib/useStore.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { expect } from 'chai'; +import TestRenderer from 'react-test-renderer'; +import createMockComponentContext from 'fluxible/utils/createMockComponentContext'; +import FooStore from '../../fixtures/stores/FooStore'; +import { useStore, FluxibleProvider } from '../../../'; + +describe('fluxible-addons-react', () => { + describe('useStore', () => { + it('returns fluxible store', () => { + const FooComponent = () => { + const getStateFromStore = store => store.getFoo(); + const foo = useStore('FooStore', getStateFromStore); + return

; + }; + + const context = createMockComponentContext({ stores: [FooStore] }); + + const testRenderer = TestRenderer.create( + + + + ); + + const component = testRenderer.root.findByType('p'); + + expect(component.props.id).to.deep.equal('bar'); + }); + }); +});