
Product
Socket for Jira Is Now Available
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.
react-renderless
Advanced tools
Utilities for creating and working with renderless React components.
What is a "renderless component"? A renderless component is the opposite of a stateless component. It does not implement a render method. Instead, renderless components are composed with stateless functional components to create UI elements.
<script src="https://unpkg.com/react-renderless"></script>
const { StateProvider, withRender } = reactRenderless
yarn add react-renderless
# OR
npm install --save react-renderless
// commonjs
const { StateProvider, withRender } = require("react-renderless")
// es module
import { StateProvider, withRender } from "react-renderless"
Instead of extending React.Component for renderless components, extend StateProvider.
StateProvider.propTypes = {
children: PropTypes.func, // pass either children or render
render: PropTypes.func, // pass either children or render
initialState: PropTypes.object, // optional
}
The render prop will be called with 2 arguments: (props, context) where props is {...this.props, ...this.state, ...this.handlers}. The prop should either be render or a the only child of the parent. The render prop must return an element when called (not a component class!).
Initial state: The component's initial state can be set by passing a prop or by setting an initialState getter on the class.
Handlers: An object that provides all the actions needed to modify the state. It is initiated one time, at mount. Handlers that need to be bound to the component instance should use arrow functions for declaration. (This will not create additional functions in each render.)
class SimpleState extends StateProvider {
get initialState() {
return {
foo: "bar",
};
}
get handlers() {
return {
set: (key, value) => this.setState({ [key]: value }),
};
}
}
const App = () => (
<SimpleState
render={({foo}) => <b>{foo}</b>}
initialState={{foo: 'baz'}}
/>
)
// renders "baz" because the initialState prop overrides the getter
withRender combines a container and presenter (renderless and stateless) into a new component that acts like a normal React component. Under the hood it simply passes the presenter as the render prop to the renderless component.
const Combined = withRender(MyStateProvider, MyRenderFunction)
const App = () => <Combined initialState={{foo: 'baz'}} />
withRender is curried so it can either be with 1 argument to create a factory for a stateful component or 2 to create a new component immediately.
const textStateFactory = withRender(TextState)
const TextInput = textStateFactory(Input)
const BigTextInput = textStateFactory(BigInput)
const Input = ({ text, setText }) => <input onChange={setText} value={text} />;
class Text extends StateProvider {
get handlers() {
return {
setText: e => this.setState({ text: e.target.value })
};
}
}
class UpperText extends StateProvider {
get initialState() {
return {
text: ""
};
}
get handlers() {
return {
setText: e => this.setState({ text: e.target.value.toUpperCase() })
};
}
}
class LowerText extends StateProvider {
get handlers() {
return {
setText: e => this.setState({ text: e.target.value.toLowerCase() })
};
}
}
const TextInput = props => <Text {...props}>{Input}</Text>;
const UpperTextInput = withRender(UpperText, Input);
const App = () => (
<div>
<TextInput initialState={{ text: "" }} /> TextInput <br />
<UpperTextInput /> UpperTextInput <br />
<LowerTextInput initialState={{ text: "" }} /> LowerTextInput
</div>
);
ReactDOM.render(<App />, document.body);
class Reducer extends StateProvider {
get handlers() {
const reducer = {
"foo:update": ({ foo }) => ({ foo: foo }),
"bar:inc": () => ({ bar: this.state.bar + 1 }),
"bar:dec": () => ({ bar: this.state.bar - 1 })
};
return {
action: (type, payload) => {
if (!reducer[type]) this.setState({});
this.setState(reducer[type](payload));
}
};
}
}
const App = () => (
<Reducer initialState={{ foo: "", bar: 0 }}>
{({ action, ...state }) => (
<div>
<p>
<b>Foo</b>
<input
onChange={e => action("foo:update", e.target.value)}
value={state.foo}
/>
</p>
<p>
<b>Bar</b>
<button onClick={() => action("bar:dec")}>+</button>
<span>{state.bar}</span>
<button onClick={() => action("bar:inc")}>+</button>
</p>
</div>
)}
</Reducer>
);
ReactDOM.render(<App />, document.body);
FAQs
renderless state provider utilities for react
The npm package react-renderless receives a total of 8 weekly downloads. As such, react-renderless popularity was classified as not popular.
We found that react-renderless demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket for Jira lets teams turn alerts into Jira tickets with manual creation, automated ticketing rules, and two-way sync.

Company News
Socket won two 2026 Reppy Awards from RepVue, ranking in the top 5% of all sales orgs. AE Alexandra Lister shares what it's like to grow a sales career here.

Security News
NIST will stop enriching most CVEs under a new risk-based model, narrowing the NVD's scope as vulnerability submissions continue to surge.