React wrap element with state

I created a State component to be able to use state whenever needed, even inside of stateless components:

const StatelessComponent = () => {
	return <div>
		...
		<State
			initial={{title: "", content: ""}}
			render={(title, setTitle, content, setContent) => {
				return <form>
					<input value={title} onChange={(e) => setTitle(e.target.value)}/>
					<textarea value={content} onChange={(e) => setContent(e.target.value)}/>
				</form>
			}
		/>
		...
	</div>
}

Here’s the component:

export const State = React.createClass({
  getInitialState() {
    return this.props.initial
  },
  render() {
    const {render} = this.props
        const stateInterface = {};
        Object.keys(this.state).forEach((name) => {
            stateInterface[`set${upperfirst(name)}`] = (value) => {
                this.setState({
                    [name]: value
                })
            }
        })
    return render({...this.state, ...stateInterface, ...this.props})
  }
})

Enjoy.

Update: changed implementation of State, had an early not-working version - sorry.

1 Like

Thank you for sharing the code with us. Question is: But Why ?

Use MobX instead, it’ll be much easier :slight_smile: (or Redux why not)

To be honest, with all the effort not to stay behind, I had never heard of MobX :blush:
I’m still not convinced about redux (or any centralized state management system), when it comes to state that naturally belongs to a single component. Seems like an antipattern to me. I prefer to isolate that state.

Obvious question, but: what’s wrong with just using a regular React component if you want to have access to state?

Have you tried Recompose? It has a withState container and more!

If you’re concerned about keeping your components pure, but still want state, don’t forget about PureComponent:

import React, { PureComponent } from 'react';

class MyPureComponent extends PureComponent {
  // ....
}

It’s the same as Component but it adds some logic to do shallow comparisons of props and state, and only re-render if there are inequalities.

2 Likes

My current focus is on rapid prototyping. I save a lot of time when I don’t prematurely split up a component (that is, before I need to reuse its parts). The result are somewhat deep/structured components.

As a result, often only sections of a component will need to maintain certain state, or even load certain data. What one would normally do (at least, what I’ve done for a while) in this cases is to split these sections into new components, and wrap them with a certain composer that maintains the state or loads the data (see the react-komposer, react-komposer-plus or the library that @sashko mentioned).

The point of calling this thread “wrap element with state” and not “wrap component with state” is not having to split a component in the above cases.

In case you are interested, my current pattern for data loading here is similar: wrap sections of components with a <Load> component.