React Render Props with TypeScript
- 8/11/2018
- ·
- #typescript
- #howto
- #react
React render props are a useful
tool for sharing logic across multiple components. Think of them as a special
case of higher-order component where–instead of creating new child
components–different render
methods can be injected.
Suppose we have a logical component (call it CounterDataProvider
) responsible
for managing a count
value consumed by components deeper inside the React
DOM. If we want to allow different rendering strategies for the count, we can type CounterDataProvider
to receive a render
prop.
type CounterState = {
count: number,
};
type ChildProps = CounterState & {
increment(d: number): void,
};
type CounterProps = {
render(state: ChildProps): React.ReactNode,
};
Yes, it’s exactly what it sounds like. The props we’ll pass to
CounterDataProvider
‘s props include a render
method that takes in
ChildProps
and produces a ReactNode
–the exact same signature we’d see in a
garden-variety Stateless Functional Component (SFC). And that’s exactly what we’ll
pass to render
!
import * as React from 'react';
class CounterDataProvider extends React.Component<CounterProps, CounterState> {
readonly state: CounterState = {
count: 44,
};
increment = (delta: number) =>
this.setState({ count: this.state.count + delta })
render() {
return this.props.render({
...this.state,
increment: this.increment,
});
}
}
export default () => (
<CounterDataProvider
render={(props: ChildProps) => (
<div>
<h1>Count: {props.count}</h1>
<button onClick={() => props.increment(1)}>+1</button>
<button onClick={() => props.increment(-1)}>-1</button>
</div>
)}
/>
);
If we wanted to imagine a completely different UI for the counter, no problem!
Just give render
a different SFC and away you go.
Find a demo of it all working together in the React with TypeScript repository on Github.