-
I'm trying to stick the active facet count into the header of a Panel widget, that is wrapping a RefinementList. This seems to have been added to vanilla js, but I'm not sure how to pull it off with React since Panel is a separate wrapping component: #1051 |
Beta Was this translation helpful? Give feedback.
Replies: 0 comments 7 replies
-
Hmm, that's a good idea, but indeed not a feature of React InstantSearch right now, since only There's two solutions for this right now:
What option would you prefer? |
Beta Was this translation helpful? Give feedback.
-
@Haroenv hmmm I'm thinking 1 makes sense since I'm already using the connector, I supposed I'd just end up with a |
Beta Was this translation helpful? Give feedback.
-
On second thought…a custom PanelCallbackHandler might be more straightforward at this point…but I could make either work |
Beta Was this translation helpful? Give feedback.
-
Here's how to do that: https://codesandbox.io/s/young-sunset-g1vuz Basically it's all the logic for panel normally, but changed so that instead of tracking canRefine, it tracks "count" (which is the number of isRefined true in items, it will be different per widget). Then you need to change the refinementlist widget just slightly, so that it uses the custom panel we just made custom panel codeimport React, { Component, createContext } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { createClassNames } from 'react-instantsearch-dom';
const cx = createClassNames('Panel');
const { Consumer: PanelConsumer, Provider: PanelProvider } = createContext(
function setCount() {}
);
export class Panel extends Component {
static propTypes = {
children: PropTypes.node.isRequired,
className: PropTypes.string,
header: PropTypes.node,
footer: PropTypes.node,
};
static defaultProps = {
className: '',
header: null,
footer: null,
};
state = {
count: 0,
};
setCount = nextCount => {
this.setState({ count: nextCount });
};
render() {
const { children, className, header, footer } = this.props;
const { count } = this.state;
return (
<div className={classNames(cx(''), className)}>
{header && <div className={cx('header')}>{header}</div>}
<pre>for debug: {JSON.stringify({ count })}</pre>
<div className={cx('body')}>
<PanelProvider value={this.setCount}>{children}</PanelProvider>
</div>
{footer && <div className={cx('footer')}>{footer}</div>}
</div>
);
}
}
class PanelCallbackHandlerInner extends Component {
componentDidMount() {
this.props.setCount(this.props.count);
}
componentDidUpdate(prevProps) {
if (prevProps.count !== this.props.count) {
this.props.setCount(this.props.count);
}
}
render() {
return this.props.children;
}
}
// changed the names so the rest is more similar
export const PanelCallbackHandler = ({ items, children }) => (
<PanelConsumer>
{setCount => (
<PanelCallbackHandlerInner
setCount={setCount}
// here's the magic to make it into count
count={items.filter(item => item.isRefined).length}
>
{children}
</PanelCallbackHandlerInner>
)}
</PanelConsumer>
); custom refinement list using that panelimport React from 'react';
import { connectRefinementList } from 'react-instantsearch-dom';
// private import of the component so I don't have to copy it.
import { RefinementList } from 'react-instantsearch-dom/dist/es/components';
import { PanelCallbackHandler } from './CustomPanel';
const RefinementListWidget = props => (
<PanelCallbackHandler {...props}>
<RefinementList {...props} />
</PanelCallbackHandler>
);
export default connectRefinementList(RefinementListWidget); |
Beta Was this translation helpful? Give feedback.
-
You can change that panel to e.g. give the information to the header or something. The current panel just seems to expect element there, but components for header & footer might make more sense, where count can be shown. This panel can then obviously be changed to get more different information than just setCount & setCanRefine by making that a simple "setInformation" (or similar) which gets computed in the PanelCallbackHandler |
Beta Was this translation helpful? Give feedback.
-
@Haroenv thank you SO much! This is exactly what I knew i needed to do but didn't have time to dig in and figure it out. Couple notes:
|
Beta Was this translation helpful? Give feedback.
-
Yes, makes sense. I think we still can’t generalise to items (not every widget has it), but maybe we should just go for all props available from panel. The complicated part becomes if you start conditionally rendering based on that data, since then you can make infinite loops, so well need to avoid those loopholes |
Beta Was this translation helpful? Give feedback.
Here's how to do that: https://codesandbox.io/s/young-sunset-g1vuz
Basically it's all the logic for panel normally, but changed so that instead of tracking canRefine, it tracks "count" (which is the number of isRefined true in items, it will be different per widget). Then you need to change the refinementlist widget just slightly, so that it uses the custom panel we just made
custom panel code