ReactiveSearch and ReactiveMaps are fully compatible with React 16.6 and above with the 3.x releases. This release comes after the feedback we have gathered from the iterative deployment of reactivesearch in production for the dozens of our clients over the last year. In this version, we have changed the way certain props behave, and included new components. This guide will give you a brief about all the changes.
ReactiveSearch
Controlled and Uncontrolled component behaviors
To enable effective control over the components, we now support defaultValue
, value
& onChange
props. These new props enable better controlled and uncontrolled usage for all the reactivesearch components. You can read all about it here.
We don't support
defaultSelected
prop anywhere.
New Render Props
You can now customise the looks and behaviors of your components in much more flexible and declarative manner with the new render props added to reactivesearch components.
In v3, you will need to use renderItem
& render
to custom render the result UI.
We've removed rendering support with
onData
andonAllData
. Although onData still exists to enable side-effects handling on new data transmissions. They act as callback props which gets triggered whenever there is a change in the data.
v2.x:
<ReactiveList
react={{
and: ['CitySensor', 'SearchSensor'],
}}
componentId="SearchResult"
onData={res => <div>{res.title}</div>}
/>
v3.x:
<ReactiveList
react={{
and: ['CitySensor', 'SearchSensor'],
}}
componentId="SearchResult"
renderItem={res => <div>{res.title}</div>}
/>
Note: We have removed support for
onAllData
prop from all the result components.
We have changed the usage of ResultList
and ResultCard
to be more flexible in order to customize the layout. You can check more about ResultList and ResultCard here.
v2.x:
<ResultList
componentId="SearchResult"
dataField="original_title"
size={3}
onData={data => ({
title: (
<div
className="book-title"
dangerouslySetInnerHTML={{
__html: data.original_title,
}}
/>
),
image: data.image,
description: (
<div className="flex column justify-space-between">
by <span className="authors-list">{item.authors}</span>
</div>
),
})}
className="result-list-container"
pagination
URLParams
react={{
and: 'BookSensor',
}}
/>
v3.x:
<ReactiveList
componentId="SearchResult"
dataField="original_title"
size={3}
className="result-list-container"
pagination
URLParams
react={{
and: 'BookSensor',
}}
render={({ data }) => (
<ReactiveList.ResultListWrapper>
{data.map(item => (
<ResultList key={item._id}>
<ResultList.Image src={item.image} />
<ResultList.Content>
<ResultList.Title>
<div
className="book-title"
dangerouslySetInnerHTML={{
__html: item.original_title,
}}
/>
</ResultList.Title>
<ResultList.Description>
<div className="flex column justify-space-between">
by <span className="authors-list">{item.authors}</span>
</div>
</ResultList.Description>
</ResultList.Content>
</ResultList>
))}
</ReactiveList.ResultListWrapper>
)}
/>
We have added the support for renderError
in all the data driven components which can be used to display error message whenever there is an error while fetching the data for that particular component.
<DataSearch
componentId="SearchSensor"
dataField={['group_venue', 'group_city']}
renderError={error => (
<div>
Something went wrong with DataSearch!
<br />
Error details
<br />
{error}
</div>
)}
/>
To allow managing the side-effects on error occurrence, we also support onError
method which gets triggered whenever an error occurs.
In v3, we have added support for parseSuggestion
& render
to customise the rendering of suggestions in the search components. This can effectively help you render custom UI in place of vanilla suggestions. We also support onSuggestion
prop which can be used to listen for the changes in suggestions & trigger side effects if required.
v2.x:
<DataSearch
onSuggestion={suggestion => ({
label: (
<div>
{suggestion._source.original_title} by
<span style={{ color: 'dodgerblue', marginLeft: 5 }}>
{suggestion._source.authors}
</span>
</div>
),
value: suggestion._source.original_title,
source: suggestion._source, // for onValueSelected to work with onSuggestion
})}
/>
v3.x:
<DataSearch
parseSuggestion={suggestion => ({
label: (
<div>
{suggestion._source.original_title} by
<span style={{ color: 'dodgerblue', marginLeft: 5 }}>
{suggestion._source.authors}
</span>
</div>
),
value: suggestion._source.original_title,
source: suggestion._source, // for onValueSelected to work with parseSuggestion
})}
renderNoSuggestion={() => <div>No Suggestions for the search term!</div>}
/>
We also added support for renderNoSuggestion
to give feedback to the user when there are no suggestions for a given search query. Please check the relevant search component docs for further details.
In v3, we have added support for renderItem
to provide custom rendering for radio, checklist, dropdown list items UIs.
We have removed support for
renderListItem
prop here. UserenderItem
instead.
v2.x:
<MultiList
componentId="CitySensor"
dataField="group.group_city.raw"
title="Cities"
renderListItem={(label, count) => (
<div>
{label}
<span style={{ marginLeft: 5, color: 'dodgerblue' }}>{count}</span>
</div>
)}
/>
v3.x:
<MultiList
componentId="CitySensor"
dataField="group.group_city.raw"
title="Cities"
renderItem={(label, count, isChecked) => (
<div className={isChecked ? 'active' : ''}>
{label}
<span style={{ marginLeft: 5, color: 'dodgerblue' }}>{count}</span>
</div>
)}
/>
In v3 we have introduced render
prop and have deprecated the use of Child component.
We've removed support of
onAllData
. Although onData still exists to enable side-effects handling on new data transmissions. They act as callback props which gets triggered whenever there is a change in the data.
v2.x
<ReactiveComponent
componentId="myColorPicker"
defaultQuery={() => ({
aggs: {
color: {
terms: {
field: 'color',
},
},
},
})}
>
<ColorPickerWrapper />
</ReactiveComponent>
v3.x
<ReactiveComponent
componentId="myColorPicker"
defaultQuery={() => ({
aggs: {
color: {
terms: {
field: 'color',
},
},
},
})}
render={({ aggregations, setQuery }) => (
<ColorPickerWrapper aggregations={aggregations} setQuery={setQuery} />
)}
/>
Standardized usage of custom and default queries
ReactiveSearch now internally validates the user-provided queries and compute the aggregation, sort, or generic queries based on the input provided. This intents to provide a seamless development experience to the developers for customizing the behaviors of the reactivesearch components. You can catch the details of this enhancement here.
defaultQuery
is ideally used with data-driven components to impact their own data.
For example, in a SingleList
component showing list of cities you may only want to render cities belonging to India.
defaultQuery = {() => ({
query: {
terms: {
country: [ "India" ]
}
}
})
}
customQuery
is used to change the component's behavior for its subscribers. It gets triggered after an interaction on the component. Every component is shipped with a default behavior i.e. selecting a city on the SingleList component generates a term query. If you wish to change this behavior i.e. maybe perform additional query besides term
query or do something else altogether, you can use customQuery
prop.
customQuery = {() => ({
query: {
term: {
user : "Kimchy"
}
}
})
}
ReactiveMaps
New Components
In v3, we have added support for OpenStreetMaps along with GoogleMaps. To optimize the final build based on the map that you would like to integrate, we are now exporting ReactiveGoogleMap
and ReactiveOpenStreetMap
instead of ReactiveMap
. This helps with tree shaking, by removing unnecessary imports based on the map that you are using. Most of the props for ReactiveGoogleMap
remains same as ReactiveMap
from v2
, there are few additional props introduced for ReactiveOpenStreetMap
based on its library requirement, you can check here.
v2:
import { ReactiveMap } from '@appbaseio/reactivemaps';
<ReactiveMap componentId="MapUI" dataField="location" title="Venue Location Map" />;
v3:
import { ReactiveGoogleMap } from '@appbaseio/reactivemaps';
<ReactiveGoogleMap componentId="MapUI" dataField="location" title="Venue Location Map" />;
OR
import { ReactiveOpenStreetMap } from '@appbaseio/reactivemaps';
<ReactiveOpenStreetMap componentId="MapUI" dataField="location" title="Venue Location Map" />;
NOTE
GeoDistanceSlider
andGeoDistanceDropdown
have also been updated and are now compatible with react >= v16.6. They also support same controlled and uncontrolled behaviour mentioned above in the guide.
ReactiveMaps 3 is published π with new features and is easier than ever to setup and use. This guide talks about what has changed in 3.0.0 and how should you as a user be switching to a 3.x stable version without breaking things.
Behind the scenes, we have switched from using the unmaintained
react-google-maps
to a maintained rewrite in the@react-google-maps/api
library.
Component API changes
The following API changes apply to both ReactiveGoogleMap and ReactiveOpenStreetMap components.
renderAllData
changes torender
prop.-
before
renderAllData={(hits, loadMore, renderMap, renderPagination, triggerClickAnalytics, meta) => { return( <> {hits.map(hit => <pre onClick={() => triggerClickAnalytics(hit._click_id)}>{JSON.stringify(hit)}</pre>)} {renderMap()} </> ) }
-
after
render={(props) => { const { data: hits, // parsed hits loading, error, promotedData, customData, rawData, resultStats: { numberOfResults numberOfPages currentPage displayedResults time hidden promoted }, loadMore // func to load more results triggerClickAnalytics // to trigger click analytics setPage, renderMap // allow users to render the map component at any place renderPagination // allows to render pagination component after displaying results } = props; return( <> {data.map(hit => <pre onClick={() => triggerClickAnalytics(hit._click_id)}>{JSON.stringify(hit)}</pre>)} {renderMap()} </pre> ) }
-
renderData
changes torenderItem
prop-
before
renderData={result => ({ custom: (<div>{result.mag}</div>), })}
-
after
renderItem={result => ({ custom: (<div>{result.mag}</div>), })}
-
Script Loading
ReactiveMaps now takes the responsibility of loding the script by itself instead of letting the user add a script tag in head of the site's html file.
Now, just pass the secret google key to the ReactiveBase
wrapper component using mapKey
prop and that's it.
-
before
<html> <head> <script src="_GOOGLE_SCRIPT_LINK"></script> </head> </html>
-
after
<ReactiveBase mapKey="<YOUR_MAP_KEY>" > </ReactiveBase>
Additionally, pass the mapLibraries
prop to load additional google libraries like places
, visualization
, and more. The following values can be set as per the Google Maps API Docs:
- drawing
- geometry
- localContext
- places
- visualization
<ReactiveBase
mapKey="<YOUR_MAP_KEY>"
mapLibraries={['visualization', 'places']}
// ...other props
/>
It's required to pass
mapLibraries={['places']}
when using either GeoDistanceDropdown or GeoDistanceSlider components from ReactiveMaps πΊοΈ .