Prop Getters is a technique that allows you to hide away the implementation details of how specific prop collections get passed to components, while still affording some composability to your props. In particular, they are useful when you have prop collections that need to interact with props passed by the parent. For example:
class Toggle extends React.Component {
/* a method for getting togglerProps.
by default, props is an empty object */
getTogglerProps = ({ onClick, ...props } = {}) => {
return {
"aria-expanded": this.state.on,
onClick: (...args) => {
/* check if an onClick prop was passed by the parent.
if so, execute it with passed arguments and then resume
standard execution by calling this.toggle */
onClick && onClick(...args);
this.toggle(...args);
},
// spread all other props from the parent
...props
};
};
render() {
return this.props.render({
on: this.state.on,
toggle: this.toggle,
// use a prop getter to supply props
getTogglerProps: this.getTogglerProps
});
}
}
// rather than passing toggleProps, let's pass a function to act as a prop getter
function App() {
return (
<Toggle
onToggle={on => console.log("toggle", on)}
render={({ on, toggle, togglerProps }) => (
<div>
<Switch on={on} {...getTogglerProps()} />
<hr />
{/* add some functionality to onClick by specifying it as an arg to getToggleProps */}
<button
{...getTogglerProps({
onClick: () => alert("hi")
})}
>
{on ? "on" : "off"}
</button>
</div>
)}
/>
);
}You can also abstract this into a utility to make it easier to manage. For example:
const compose = (...fns) => (...args) => fns.forEach(fn => fn && fn(...args));
// this.getTogglerProps becomes...
getTogglerProps = ({ onClick, ...props } = {}) => {
return {
"aria-expanded": this.state.on,
onClick: compose(onClick, this.toggle),
// spread all other props from the parent
...props
};
};