Skip to content
This repository has been archived by the owner on Dec 30, 2022. It is now read-only.

refactor(InstantSearch): migrate life cycles #2349

Merged
merged 57 commits into from
Jun 17, 2019
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
06efa75
feat(client): remove algoliaClient alias
Haroenv Apr 15, 2019
0012284
chore(error): remove duplicate colon
Haroenv Apr 17, 2019
6deac03
docs(examples): use searchClient everywhere
Haroenv Apr 17, 2019
f0a0593
feat(searchClient): remove other options
Haroenv Apr 17, 2019
7677f02
adds back user agent tests & remove defaultAlgoliaClient
Haroenv Apr 17, 2019
7e81f7f
remove algoliasearch from dependencies
Haroenv Apr 17, 2019
0ec315f
remove algoliasearch usage
Haroenv Apr 17, 2019
0453b9d
chore: update max size
Haroenv Apr 17, 2019
4953745
refactor(root): remove createIndex & createInstantSearch
Haroenv Apr 17, 2019
8787dd8
add default state to Index
Haroenv Apr 18, 2019
3029b5f
fix tests
Haroenv Apr 18, 2019
ae5586d
remove useless types
Haroenv Apr 18, 2019
b1de630
changes to make tests pass again
Haroenv Apr 18, 2019
bb5fc85
move addAlgoliaAgent
Haroenv Apr 18, 2019
5f73bd3
temp: breaks everything
Haroenv Apr 19, 2019
2f250ec
make tests pass
Haroenv Apr 19, 2019
f43fb26
remove constructor
Haroenv Apr 19, 2019
edb5463
fix(propTypes): more strict searchClient type
Haroenv May 22, 2019
38f7c81
chore(examples): add algoliasearch as dependency
Haroenv May 22, 2019
18e4549
chore(stories): memoize search client
Haroenv May 22, 2019
6cae753
chore: update proptype
Haroenv May 22, 2019
0f22dfe
refactor(root): remove createIndex & createInstantSearch
Haroenv Apr 17, 2019
25aa42b
add default state to Index
Haroenv Apr 18, 2019
70a01c5
fix tests
Haroenv Apr 18, 2019
6a4e4ff
remove useless types
Haroenv Apr 18, 2019
60d41b9
changes to make tests pass again
Haroenv Apr 18, 2019
e77cd02
move addAlgoliaAgent
Haroenv Apr 18, 2019
a8015cb
Merge branch 'refactor/factory' into refactor/instantsearch-lc
Haroenv May 22, 2019
a95b47e
chore: update size
Haroenv May 22, 2019
f3b3d5b
Merge branch 'refactor/factory' into refactor/instantsearch-lc
Haroenv May 22, 2019
1810178
refactor(root): remove createIndex & createInstantSearch
Haroenv Apr 17, 2019
67497be
Merge branch 'refactor/factory' into refactor/instantsearch-lc
Haroenv May 23, 2019
5fd207f
test: update tests
Haroenv May 24, 2019
3dc85cf
refactor(root): move Index and InstantSearch to widgets
yannickcr Jun 4, 2019
4151ebb
refactor(root): remove addAlgoliaAgents export
yannickcr Jun 4, 2019
b95c15a
refactor(root): update Index documentation
yannickcr Jun 4, 2019
c49aeb2
refactor(root): init multiIndexContext using indexContext from state
yannickcr Jun 4, 2019
b701487
refactor(root): add comment in user agents test
yannickcr Jun 5, 2019
d4f9b3d
update enzyme
yannickcr Jun 5, 2019
c5ef054
move isControlled check in cDU
yannickcr Jun 5, 2019
c01703b
move updateIndex and updateClient in cDU
yannickcr Jun 5, 2019
61f7cd4
do not clear cache if refresh was already true
yannickcr Jun 5, 2019
61e1ecd
remove check in updateClient
yannickcr Jun 5, 2019
eedef1e
remove refreshValue
yannickcr Jun 5, 2019
574de2b
refactor(root): remove unused InstantSearch component
yannickcr Jun 5, 2019
77e31d0
Export InstantSearch from react-instantsearch-core
yannickcr Jun 12, 2019
cdef88c
Remove isControlled from state
yannickcr Jun 12, 2019
39b4d96
Add test for refresh
yannickcr Jun 12, 2019
192b63e
Remove extraneous check
yannickcr Jun 12, 2019
4a8db0b
Merge branch 'refactor/factory' into refactor/instantsearch-lc
yannickcr Jun 12, 2019
650a227
Merge branch 'v6' into refactor/factory
yannickcr Jun 14, 2019
56242d7
Merge branch 'refactor/factory' into refactor/instantsearch-lc
yannickcr Jun 14, 2019
e370ff8
Merge branch 'v6' into refactor/factory
yannickcr Jun 17, 2019
738aecb
Fix comment
yannickcr Jun 17, 2019
0088c41
Update bundlesize
yannickcr Jun 17, 2019
897b370
Merge branch 'refactor/factory' into refactor/instantsearch-lc
yannickcr Jun 17, 2019
0ab7249
Merge branch 'v6' into refactor/instantsearch-lc
yannickcr Jun 17, 2019
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
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"conventional-changelog-cli": "2.0.12",
"copy-webpack-plugin": "5.0.2",
"css-loader": "2.1.1",
"enzyme": "3.9.0",
"enzyme": "3.10.0",
"enzyme-adapter-react-16": "1.12.1",
"enzyme-to-json": "3.3.5",
"eslint": "5.16.0",
Expand Down Expand Up @@ -129,7 +129,7 @@
},
{
"path": "packages/react-instantsearch/dist/umd/Connectors.min.js",
"maxSize": "41 kB"
"maxSize": "42 kB"
},
{
"path": "packages/react-instantsearch/dist/umd/Dom.min.js",
Expand Down
63 changes: 24 additions & 39 deletions packages/react-instantsearch-core/src/components/Index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Component, Children, ReactType } from 'react';
import React, { Component, Children } from 'react';
import PropTypes from 'prop-types';
import {
InstantSearchConsumer,
Expand All @@ -7,13 +7,15 @@ import {
IndexContext,
} from '../core/context';

function getIndexContext(props: Props): IndexContext {
return {
targetedIndex: props.indexId || props.indexName,
};
}

type Props = {
indexName: string;
indexId: string;
root: {
Root: ReactType;
props: {};
};
indexId?: string;
};

type InnerProps = Props & { contextValue: InstantSearchContext };
Expand All @@ -29,7 +31,6 @@ type State = {
* @kind widget
* @name <Index>
* @propType {string} indexName - index in which to search.
* @propType {{ Root: string|function, props: object }} [root] - Use this to customize the root element. Default value: `{ Root: 'div' }`
* @example
* import React from 'react';
* import algoliasearch from 'algoliasearch/lite';
Expand Down Expand Up @@ -58,36 +59,31 @@ type State = {
*/
class Index extends Component<InnerProps, State> {
static propTypes = {
// @TODO: These props are currently constant.
indexName: PropTypes.string.isRequired,
indexId: PropTypes.string.isRequired,
indexId: PropTypes.string,
children: PropTypes.node,
root: PropTypes.shape({
Root: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.object,
]),
props: PropTypes.object,
}).isRequired,
};

unregisterWidget?: () => void;
static getDerivedStateFromProps(props: InnerProps) {
return {
indexContext: getIndexContext(props),
};
}

state = {
indexContext: {
targetedIndex: this.props.indexId,
},
indexContext: getIndexContext(this.props),
};

unregisterWidget?: () => void;

constructor(props: InnerProps) {
super(props);

this.props.contextValue.onSearchParameters(
this.getSearchParameters.bind(this),
{
ais: this.props.contextValue,
multiIndexContext: this.state.indexContext,
multiIndexContext: getIndexContext(props),
},
this.props
);
Expand All @@ -99,18 +95,10 @@ class Index extends Component<InnerProps, State> {
);
}

componentWillReceiveProps(nextProps: InnerProps) {
// @TODO: DidUpdate
if (this.props.indexName !== nextProps.indexName) {
componentDidUpdate(prevProps: InnerProps) {
if (this.props.indexName !== prevProps.indexName) {
this.props.contextValue.widgetsManager.update();
}
if (this.props.indexId !== nextProps.indexId) {
this.setState({
indexContext: {
targetedIndex: nextProps.indexId,
},
});
}
}

componentWillUnmount() {
Expand All @@ -119,24 +107,21 @@ class Index extends Component<InnerProps, State> {
}
}

getSearchParameters(searchParameters, props) {
getSearchParameters(searchParameters, props: InnerProps) {
return searchParameters.setIndex(
this.props ? this.props.indexName : props.indexName
);
}

render() {
const childrenCount = Children.count(this.props.children);
const { Root, props } = this.props.root;
if (childrenCount === 0) {
return null;
}
return (
<Root {...props}>
<IndexProvider value={this.state.indexContext}>
{this.props.children}
</IndexProvider>
</Root>
<IndexProvider value={this.state.indexContext}>
{this.props.children}
</IndexProvider>
);
}
}
Expand Down
153 changes: 70 additions & 83 deletions packages/react-instantsearch-core/src/components/InstantSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,11 @@
import React, { Component, Children, ReactType } from 'react';
import React, { Component, Children } from 'react';
import PropTypes from 'prop-types';
import createInstantSearchManager from '../core/createInstantSearchManager';
import { InstantSearchProvider, InstantSearchContext } from '../core/context';
import { Store } from '../core/createStore';

function validateNextProps(props, nextProps) {
if (!props.searchState && nextProps.searchState) {
throw new Error(
"You can't switch <InstantSearch> from being uncontrolled to controlled"
);
} else if (props.searchState && !nextProps.searchState) {
throw new Error(
"You can't switch <InstantSearch> from being controlled to uncontrolled"
);
}
function isControlled(props: Props) {
return Boolean(props.searchState);
}

// @TODO: move this to the helper?
Expand Down Expand Up @@ -61,14 +53,11 @@ type Props = {
searchState: SearchState
) => void;
stalledSearchDelay?: number;
root: {
Root: ReactType;
props: {};
};
resultsState: SearchResults | { [indexId: string]: SearchResults };
};

type State = {
isControlled: boolean;
samouss marked this conversation as resolved.
Show resolved Hide resolved
contextValue: InstantSearchContext;
};

Expand Down Expand Up @@ -113,6 +102,7 @@ type State = {
class InstantSearch extends Component<Props, State> {
static defaultProps = {
stalledSearchDelay: 200,
refresh: false,
};

static propTypes = {
Expand All @@ -128,7 +118,7 @@ class InstantSearch extends Component<Props, State> {

createURL: PropTypes.func,

refresh: PropTypes.bool.isRequired,
refresh: PropTypes.bool,

searchState: PropTypes.object,
onSearchStateChange: PropTypes.func,
Expand All @@ -137,77 +127,77 @@ class InstantSearch extends Component<Props, State> {
resultsState: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),

children: PropTypes.node,

root: PropTypes.shape({
Root: PropTypes.oneOfType([
PropTypes.string,
PropTypes.func,
PropTypes.object,
]),
props: PropTypes.object,
}).isRequired,

stalledSearchDelay: PropTypes.number,
};

isControlled: boolean;
isUnmounting: boolean;
aisManager: InstantSearchManager;

constructor(props: Props) {
super(props);
this.isControlled = Boolean(props.searchState);
const initialState = this.isControlled ? props.searchState : {};
this.isUnmounting = false;

this.aisManager = createInstantSearchManager({
indexName: props.indexName,
searchClient: props.searchClient,
initialState,
resultsState: props.resultsState,
stalledSearchDelay: props.stalledSearchDelay,
});

this.state = {
static getDerivedStateFromProps(
nextProps: Props,
prevState: State
): Partial<State> {
return {
contextValue: {
onInternalStateUpdate: this.onWidgetsInternalStateUpdate.bind(this),
createHrefForState: this.createHrefForState.bind(this),
onSearchForFacetValues: this.onSearchForFacetValues.bind(this),
onSearchStateChange: this.onSearchStateChange.bind(this),
onSearchParameters: this.onSearchParameters.bind(this),
store: this.aisManager.store,
widgetsManager: this.aisManager.widgetsManager,
mainTargetedIndex: this.props.indexName,
...prevState.contextValue,
mainTargetedIndex: nextProps.indexName,
},
};
}

componentWillReceiveProps(nextProps) {
// @TODO: DidUpdate
validateNextProps(this.props, nextProps);

if (this.props.indexName !== nextProps.indexName) {
this.aisManager.updateIndex(nextProps.indexName);
this.setState(state => ({
contextValue: {
...state.contextValue,
mainTargetedIndex: nextProps.indexName,
},
}));
isUnmounting: boolean = false;
aisManager: InstantSearchManager = createInstantSearchManager({
samouss marked this conversation as resolved.
Show resolved Hide resolved
indexName: this.props.indexName,
searchClient: this.props.searchClient,
initialState: this.props.searchState || {},
resultsState: this.props.resultsState,
stalledSearchDelay: this.props.stalledSearchDelay,
});

state = {
isControlled: isControlled(this.props),
contextValue: {
onInternalStateUpdate: this.onWidgetsInternalStateUpdate.bind(this),
createHrefForState: this.createHrefForState.bind(this),
onSearchForFacetValues: this.onSearchForFacetValues.bind(this),
onSearchStateChange: this.onSearchStateChange.bind(this),
onSearchParameters: this.onSearchParameters.bind(this),
store: this.aisManager.store,
widgetsManager: this.aisManager.widgetsManager,
mainTargetedIndex: this.props.indexName,
},
};

componentDidUpdate(prevProps: Props) {
const nextIsControlled = isControlled(this.props);

if (!this.state.isControlled && nextIsControlled) {
throw new Error(
"You can't switch <InstantSearch> from being uncontrolled to controlled"
);
}

if (this.props.refresh !== nextProps.refresh) {
if (nextProps.refresh) {
this.aisManager.clearCache();
}
if (this.state.isControlled && !nextIsControlled) {
throw new Error(
"You can't switch <InstantSearch> from being controlled to uncontrolled"
);
}

if (this.props.searchClient !== nextProps.searchClient) {
this.aisManager.updateClient(nextProps.searchClient);
/*
* Clear cache when `refresh` changes to `true`.
* Prevents users to always clear the cache on render if they forget to revert it to `false`.
*/
if (this.props.refresh !== prevProps.refresh && this.props.refresh) {
samouss marked this conversation as resolved.
Show resolved Hide resolved
this.aisManager.clearCache();
}

if (this.isControlled) {
this.aisManager.onExternalStateUpdate(nextProps.searchState);
if (this.state.isControlled) {
this.aisManager.onExternalStateUpdate(this.props.searchState);
}

if (prevProps.indexName !== this.props.indexName) {
this.aisManager.updateIndex(this.props.indexName);
}

if (prevProps.searchClient !== this.props.searchClient) {
this.aisManager.updateClient(this.props.searchClient);
}
}

Expand All @@ -218,7 +208,7 @@ class InstantSearch extends Component<Props, State> {

createHrefForState(searchState: SearchState) {
searchState = this.aisManager.transitionState(searchState);
return this.isControlled && this.props.createURL
return this.state.isControlled && this.props.createURL
? this.props.createURL(searchState, this.getKnownKeys())
: '#';
}
Expand All @@ -228,7 +218,7 @@ class InstantSearch extends Component<Props, State> {

this.onSearchStateChange(searchState);

if (!this.isControlled) {
if (!this.state.isControlled) {
this.aisManager.onExternalStateUpdate(searchState);
}
}
Expand Down Expand Up @@ -260,17 +250,14 @@ class InstantSearch extends Component<Props, State> {
}

render() {
const childrenCount = Children.count(this.props.children);
const { Root, props } = this.props.root;
if (childrenCount === 0) {
if (Children.count(this.props.children) === 0) {
return null;
}

return (
<Root {...props}>
<InstantSearchProvider value={this.state.contextValue}>
{this.props.children}
</InstantSearchProvider>
</Root>
<InstantSearchProvider value={this.state.contextValue}>
{this.props.children}
</InstantSearchProvider>
);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ describe('Index', () => {
it('calls update if indexName prop changes', () => {
const context = createContext();

const wrapper = shallow(
// componentDidUpdate wasn't called on `shallow`
const wrapper = mount(
<IndexComponentWithoutContext {...requiredProps} contextValue={context}>
<div />
</IndexComponentWithoutContext>
Expand Down
Loading