Skip to content

Commit

Permalink
global: expose updateQueryState
Browse files Browse the repository at this point in the history
- updateQueryState exposed withState HOC
- test for exposed props form withState
- documentation
- fix for config expecting axios property
- fix circular dependency src/lib/store.js -> src/lib/state/reducers/index.js -> src/lib/state/reducers/query.js -> src/lib/store.js
- changed initialResultsState.loading to true to avoid double children render in ResultsLoader closes #101
- closes #99
  • Loading branch information
topless committed Mar 31, 2020
1 parent 1f79c1b commit 90e015e
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 47 deletions.
34 changes: 18 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,19 @@ React-SearchKit is a React library that allows you to build in an easy way your

Main features:

* ready-to-use collection of UI components
* configurable REST API endpoint and serialization
* configurable URL parameters handling for deep linking
- ready-to-use collection of UI components
- configurable REST API endpoint and serialization
- configurable URL parameters handling for deep linking

![React-SearchKit screenshot](docs/website/static/img/screenshot.png)

## Examples

You can find a collection of examples in the `src/demos` folder:

* Elasticsearch, an example on how to query Elasticsearch (see below)
* Zenodo.org, an example on how to query an Invenio 3 instance
* CERN Videos, another Invenio 3 example
- Elasticsearch, an example on how to query Elasticsearch (see below)
- Zenodo.org, an example on how to query an Invenio 3 instance
- CERN Videos, another Invenio 3 example

Install dependencies and run the React app to try them out (see steps below).

Expand All @@ -40,44 +40,46 @@ To run the Elasticsearch backend for the demo, you can use Docker. A `docker-com
Run the services:

```bash
$ cd src/demos/elasticsearch/docker
$ docker-compose up
cd src/demos/elasticsearch/docker
docker-compose up
```

Then, init the demo data:

```bash
$ curl -XPUT 'http://localhost:9200/random?pretty' -H 'Content-Type: application/json' -d @es7-mappings.json
$ curl -XPOST 'http://localhost:9200/random/_bulk' -H 'Content-Type: application/json' --data-binary @es-random-data.json
$ curl -XGET 'http://localhost:9200/random/_count?pretty'
curl -XPUT 'http://localhost:9200/random?pretty' -H 'Content-Type: application/json' -d @es7-mappings.json
curl -XPOST 'http://localhost:9200/random/_bulk' -H 'Content-Type: application/json' --data-binary @es-random-data.json
curl -XGET 'http://localhost:9200/random/_count?pretty'
```

Demo data have been randomly generated using <https://next.json-generator.com>.

> In case you want to clear your elastic search from data you can use `curl -X DELETE 'http://localhost:9200/_all'`
## Developer guide

React-SearchKit uses [create-react-app](https://create-react-app.dev/) as development toolkit.

Install the library:

```
```bash
npm install
```

Start the demo application:

```
```bash
npm start
```

The library uses [Jest](https://jestjs.io/) as test runner. To run the tests:

```
```bash
npm test
```

The library uses `rollup` to build a final version inside the `/dist` folder and it will build CommonJS and ES Modules versions:

```
npm build
```bash
npm run build
```
12 changes: 9 additions & 3 deletions docs/docs/components/with_state.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,17 @@ id: with-state
title: withState
---

`withState` is a HOC component that passes the redux state to an external component.
`withState` is a high order component, which is used to expose the redux state and
actions to external components.

The component receives the up-to-date state every time something is changed.
The component receives the up-to-date state every time something is changed and
through its props it gains access to

> Do **not** mutate the state inside your wrapped component!
- `currentResultsState`
- `currentQueryState`
- `updateQueryState`

> Do **not** mutate directly the state inside your wrapped component. Instead, use the function `updateQueryState` to pass your new query.
## Usage

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
},
"dependencies": {},
"peerDependencies": {
"axios": "^0.19.0",
"axios": "^0.19.2",
"lodash": "^4.17.15",
"node-sass": "^4.12.0",
"qs": "^6.8.0",
Expand All @@ -32,7 +32,7 @@
"devDependencies": {
"@babel/cli": "^7.5.5",
"@svgr/rollup": "^4.3.2",
"axios": "^0.19.0",
"axios": "^0.19.2",
"axios-mock-adapter": "^1.17.0",
"coveralls": "^3.0.7",
"enzyme": "^3.10.0",
Expand Down
6 changes: 4 additions & 2 deletions src/demos/cern-videos/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,10 @@ const resultsPerPageValues = [
];

const searchApi = new InvenioSearchApi({
url: 'https://videos.cern.ch/api/records/',
timeout: 5000,
axios: {
url: 'https://videos.cern.ch/api/records/',
timeout: 5000,
},
});

export class App extends Component {
Expand Down
6 changes: 4 additions & 2 deletions src/demos/elasticsearch/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import { ESSearchApi } from '../../lib/api/contrib/elasticsearch';
const OnResults = withState(Results);

const searchApi = new ESSearchApi({
url: 'http://localhost:5000/random/_search',
timeout: 5000,
axios: {
url: 'http://localhost:5000/random/_search',
timeout: 5000,
},
es: {
requestSerializer: DemoESRequestSerializer,
},
Expand Down
8 changes: 5 additions & 3 deletions src/demos/zenodo/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,11 @@ const resultsPerPageValues = [
];

const searchApi = new InvenioSearchApi({
url: 'https://zenodo.org/api/records/',
timeout: 5000,
headers: { Accept: 'application/vnd.zenodo.v1+json' },
axios: {
url: 'https://zenodo.org/api/records/',
timeout: 5000,
headers: { Accept: 'application/vnd.zenodo.v1+json' },
},
});

export class App extends Component {
Expand Down
10 changes: 6 additions & 4 deletions src/lib/components/HOC/withState.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import React from 'react';
import { connect } from '../../store';
import { updateQueryState } from '../../state/actions';

export function withState(Component) {
const WrappedComponent = ({ dispatch, ...props }) => <Component {...props} />;
Expand All @@ -16,8 +17,9 @@ export function withState(Component) {
currentResultsState: state.results,
});

return connect(
mapStateToProps,
null
)(WrappedComponent);
const mapDispatchToProps = dispatch => ({
updateQueryState: queryState => dispatch(updateQueryState(queryState)),
});

return connect(mapStateToProps, mapDispatchToProps)(WrappedComponent);
}
33 changes: 33 additions & 0 deletions src/lib/components/HOC/withState.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* This file is part of React-SearchKit.
* Copyright (C) 2020 CERN.
*
* React-SearchKit is free software; you can redistribute it and/or modify it
* under the terms of the MIT License; see LICENSE file for more details.
*/

import React from 'react';
import configureMockStore from 'redux-mock-store';
import { shallow } from 'enzyme';
import { withState } from './withState';

const mockStore = configureMockStore();

describe('withState tests', () => {
let WithStateComponent;
let store;
beforeEach(() => {
store = mockStore({});
store.clearActions();
const mockedComponent = jest.fn();
WithStateComponent = withState(mockedComponent);
});

it('should find the props exposed by withState', async () => {
const wrapper = shallow(<WithStateComponent store={store} />);
const props = wrapper.children(0).props();
expect(props.hasOwnProperty('currentResultsState')).toBe(true);
expect(props.hasOwnProperty('currentQueryState')).toBe(true);
expect(props.hasOwnProperty('updateQueryState')).toBe(true);
});
});
2 changes: 1 addition & 1 deletion src/lib/state/reducers/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import {
RESET_QUERY,
} from '../types';
import { updateQueryFilters, updateQueryState } from '../selectors';
import { STORE_KEYS } from '../../store';
import { STORE_KEYS } from '../../storeConfig';

export default (state = {}, action) => {
switch (action.type) {
Expand Down
16 changes: 2 additions & 14 deletions src/lib/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,13 @@ import { connect } from 'react-redux';
import thunk from 'redux-thunk';

import rootReducer from './state/reducers';

export const INITIAL_STORE_STATE = {
queryString: '',
suggestions: [],
sortBy: null,
sortOrder: null,
page: 1,
size: 10,
filters: [],
layout: null,
};

export const STORE_KEYS = Object.keys(INITIAL_STORE_STATE);
import { INITIAL_STORE_STATE } from './storeConfig';

export function configureStore(appConfig) {
const initialQueryState = INITIAL_STORE_STATE;

const initialResultsState = {
loading: false,
loading: true,
data: {
hits: [],
total: 0,
Expand Down
20 changes: 20 additions & 0 deletions src/lib/storeConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* This file is part of React-SearchKit.
* Copyright (C) 2018-2020 CERN.
*
* React-SearchKit is free software; you can redistribute it and/or modify it
* under the terms of the MIT License; see LICENSE file for more details.
*/

export const INITIAL_STORE_STATE = {
queryString: '',
suggestions: [],
sortBy: null,
sortOrder: null,
page: 1,
size: 10,
filters: [],
layout: null,
};

export const STORE_KEYS = Object.keys(INITIAL_STORE_STATE);

0 comments on commit 90e015e

Please sign in to comment.