Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,27 @@ const ConnectedComponent = reduxAutoloader({
})(ExampleComponent);
```

#### Reload (refresh) all active loaders

To create a "refresh all" button, simply use `collection` HOC instead of `reduxAutoloader` one. It has the same signature.

```jsx
import { collection } from 'redux-autoloader';

const ConnectedComponent = collection(options)(ExampleComponent);
```

Then you can create a refresh button like using `withCollection` that passes a global `.refresh()` method as a prop.

```jsx
import { withCollection } from 'redux-autoloader';

const ExampleComponent = ({ refresh }) => {
return <button onClick={refresh} />Reload</button>;
};

const ReloadComoponent = withCollection(ExampleComponent);
```

## API Documentation

Expand Down
75 changes: 75 additions & 0 deletions src/collection.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/* eslint-disable react/no-unused-prop-types,
react/prefer-stateless-function,
react/forbid-prop-types
*/
import { PureComponent, createElement } from 'react';
import PropTypes from 'prop-types';
import getDisplayName from 'react-display-name';
import reduxAutoloader from './reduxAutoloader';

import { assert } from './utils';

const hashTable = {};

export const collection = (options, mapStateToProps = state => state) => {
const name = options.name;

assert(name, 'name is required');
assert(typeof name === 'function' || typeof name === 'string', 'name must be a function or a string');
assert(typeof mapStateToProps === 'function', 'selector must be a function');

const getReducerName = typeof name === 'function' ? name : () => name;

return (WrappedComponent) => {
class CollectionComponent extends PureComponent {
static propTypes = {
$refresh: PropTypes.func.isRequired,
$name: PropTypes.string.isRequired,
};

componentDidMount() {
hashTable[this.props.$name] = this.props.$refresh;
}

componentWillReceiveProps(nextProps) {
if (nextProps.$refresh !== this.props.$refresh) {
if (this.props.$name !== nextProps.$name) {
delete hashTable[this.props.$name];
}

hashTable[nextProps.$name] = nextProps.$refresh;
}
}

componentWillUnmount() {
delete hashTable[this.props.$name];
}

render() {
const { $name, $refresh, ...props } = this.props; // eslint-disable-line no-unused-vars
return createElement(WrappedComponent, props);
}
}

CollectionComponent.displayName = `collection-${getDisplayName(WrappedComponent)}`;
CollectionComponent.WrappedComponent = WrappedComponent;

return reduxAutoloader(options, (state, props) => ({
$name: getReducerName(props),
$refresh: state.refresh,
...mapStateToProps(state),
}))(CollectionComponent);
};
};

const refresh = () => {
Object.values(hashTable).forEach(loader => loader());
};

export const withCollection = (WrappedComponent) => {
const WithCollection = props => createElement(WrappedComponent, { ...props, refresh });

WithCollection.displayName = `withCollection-${getDisplayName(WrappedComponent)}`;

return WithCollection;
};
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export reducer from './reducer';
export * from './selectors';
export * from './actions';
export reduxAutoloader from './reduxAutoloader';
export * from './collection';