Tools for connecting high-level Redux components (“Bricks”).
npm install --save @modular-toolkit/bricks
Note: by default, the npm package exposes ES5-compatible code (transpiled through Babel).
If you want to use the untranspiled code (highly recommended), us the esnext version, which is included in the same npm package (more info here).
The Brick Manager allows you to “wire up” Bricks in your application by running each Brick's root saga with the Redux Saga middleware, preparing each Brick's selectors to work with the global Redux state, and replacing the current root Reducer with a new reducer that includes each Brick's reducer.
Here is an example taken from the demo app that shows how it is used:
demo-app/src/configureStore.js
import { applyMiddleware, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
import createInitialState from './createInitialState';
import reducer from './reducer';
import hackerNews from '@modular-toolkit/demo-module';
import gists from '@modular-toolkit/other-demo-module';
import { BrickManager } from '@modular-toolkit/bricks/BrickManager';
const initialState = createInitialState();
export default () => {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducer, initialState, applyMiddleware(sagaMiddleware));
const brickManager = new BrickManager({ store, reducer, sagaMiddleware });
brickManager.installBricks({
'bricks.hackerNews': hackerNews,
'bricks.gists': gists
});
return store;
};
This function works exactly the same as combineReducers from Dan Abramov's Redux library, except that it does not issue a warning when an initial state is encountered that contains keys for which there are no reducers defined.
Use this version of combineReducers if you want to combine reducers in your main application, while providing an initial state for Bricks that are added at a later point using the Brick Manager (e.g. when hydrating a server-side rendered page).
Here is an example taken from the demo app that shows how it is used:
demo-app/src/reducer.js
import { CHANGE_BACKGROUND_COLOR } from './actions';
import { combineReducers } from '@modular-toolkit/bricks';
export default combineReducers({
page(state = {}, action = {}) {
switch (action.type) {
case CHANGE_BACKGROUND_COLOR:
return {
...state,
backgroundColor: action.backgroundColor
};
default:
return state;
}
}
});
This context provider wrapper allows you to pass a BrickManager
instance to deep-nested components through
the React context API, similar to the Provider of
react-redux.
Important: Make sure the brick provider is inside the Redux Provider
(as shown in the example below), but always
around all other components, especially BrowserRouter
from React Router.
This example shows how to initialize Redux for your application, along with the BrickProvider
:
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { BrickProvider } from '@modular-toolkit/bricks';
import { applyMiddleware, createStore } from 'redux';
import createSagaMiddleware from 'redux-saga';
const reducer = state => state;
const sagaMiddleware = createSagaMiddleware();
const store = createStore(reducer, applyMiddleware(sagaMiddleware));
const { store, reducer, sagaMiddleware } = configureStore();
ReactDOM.render(
<Provider store={store}>
<BrickProvider store={store} reducer={reducer} sagaMiddleware={sagaMiddleware}>
<h1>Hello world!</h1>
</BrickProvider>
</Provider>,
document.getElementById('root')
);
The BrickProvider
accepts these props:
store
(required) – The redux storesagaMiddleware
(required) – The redux-saga middlewarereducer
(optional) – The application's root reducer
This function allows you to create a higher-order container component that enhances other components, installing a brick when the component is mounted. It works the same way as the connect from react-redux.
You must wrap your application with a BrickProvider for this to work.
Example:
import React from 'react';
import { withBrick } from '@modular-toolkit/bricks';
import hackerNews, { HackerNews } from '@modular-toolkit/demo-module';
function MyComponent() {
return (
<div>
Check out the latest Hacker News:
<HackerNews />
</div>
);
}
export const enhance = withBrick('bricks.hackerNews', hackerNews);
export default enhance(MyComponent);
The withBrick
function accepts three arguments:
storePath
(required, string) – The path to the part of the global Redux state that the Brick is working with; path segments are separated by dots; example:bricks.hackerNews
module
(required, object) – The brick module that contains store, reducer and saga of the brick; this is usually the default export of a brick packageinitialState
(optional, object) – An initial state that can be used for configuration (see below)
This function allows you to create a higher-order container component that enhances other components, installing multiple bricks when the component is mounted. It works the same way as the connect from react-redux.
You must wrap your application with a BrickProvider for this to work.
This is basically the same as withBrick, except that you can install multiple bricks instead of just one by providing an object where the keys are store paths and the values are brick modules.
Example:
import React from 'react';
import { connect } from 'react-redux';
import { withBricks } from '@modular-toolkit/bricks';
import hackerNews, { HackerNews } from '@modular-toolkit/demo-module';
import gists, { Gists } from '@modular-toolkit/other-demo-module';
function MyComponent() {
return (
<div>
Check out the latest Hacker News:
<HackerNews />
…and the latest Gists:
<Gists />
</div>
);
}
export const enhance = withBricks({
'bricks.hackerNews': hackerNews,
'bricks.gists': gists
});
export default enhance(MyComponent);
The withBricks
function accepts one argument:
bricks
(required, object) – an object where the keys are store paths and the values are brick modules
In some cases, it is desirable to configure the initial state of a Brick, to pass general configuration that needs to be available when the Brick is installed.
For example, you may want to configure the base URL of an API used by a Saga to fetch data.
This can be done by passing an initial state object to the Brick Manager.
brickManager.installBrick('bricks.hackerNews', hackerNews, {
baseUrl: 'https://hackernews.com/api'
});
brickManager.installBricks({
'bricks.hackerNews': { ...hackerNews, initialState: { baseUrl: 'https://hackernews.com/api' } },
'bricks.gists': { ...gists, initialState: { baseUrl: 'https://gists.com/api' } }
});
const enhance = withBrick('bricks.hackerNews', hackerNews, {
baseUrl: 'https://hackernews.com/api'
});
const enhance = withBricks({
'bricks.hackerNews': { ...hackerNews, initialState: { baseUrl: 'https://hackernews.com/api' } },
'bricks.gists': { ...gists, initialState: { baseUrl: 'https://gists.com/api' } }
});
React version 16.7.0-alpha.0 introduces a revolutionary new feature called Hooks, which makes integrating bricks in your application much easier.
Note that the following functions only work with the React alpha version noted above. They are not recommended for production use yet – proceed at your own risk.
This Hook function allows you to install a brick from within a function React component.
You must wrap your application with a BrickProvider for this to work.
This is a Hook version of withBrick.
Example:
import React from 'react';
import hackerNews, { HackerNews } from '@modular-toolkit/demo-module';
import { useBrick } from '@modular-toolkit/bricks';
export default () => {
useBrick('bricks.hackerNews', hackerNews);
return (
<div>
Check out the latest Hacker News:
<HackerNews />
</div>
);
};
As you can see in the example, you do not need to use an enhancer to create a higher-order component. All you need is
call the useBrick
hook and the Hacker News brick is installed in your application's Redux setup and ready to use.
The useBrick
function accepts two arguments:
storePath
(required, string) – The path to the part of the global Redux state that the Brick is working with; path segments are separated by dots; example:bricks.hackerNews
module
(required, object) – The brick module that contains store, reducer and saga of the brick; this is usually the default export of a brick package
This Hook function allows you to install a brick from within a function React component.
You must wrap your application with a BrickProvider for this to work.
This is a Hook version of withBricks.
Example:
import React from 'react';
import hackerNews, { HackerNews } from '@modular-toolkit/demo-module';
import gists, { Gists } from '@modular-toolkit/other-demo-module';
import { useBricks } from '@modular-toolkit/bricks';
export default () => {
useBricks({
'bricks.hackerNews': hackerNews,
'bricks.gists': gists
});
return (
<div>
Check out the latest Hacker News:
<HackerNews />
…and the latest Gists:
<Gists />
</div>
);
};
The useBricks
function accepts one argument:
bricks
(required, object) – an object where the keys are store paths and the values are brick modules
If you get this warning in your browser console, you're using combineReducers from the Redux library. Use combineReducers from modular-toolkit instead (see above).
- See CHANGELOG.md
- See CONTRIBUTING.md
- Includes code taken from Redux (combineReducers)
MIT licensed
Copyright © 2015–present Dan Abramov - The BrickManager module is inspired by Reedux
MIT licensed
Copyright © 2017 Silviu Marian
Copyright © 2018 mobile.de GmbH