@render-props/value
Version:
A state container which provides an interface for setting single values.
117 lines (92 loc) • 2.77 kB
JavaScript
'use strict'
var _interopRequireDefault = require('@babel/runtime/helpers/interopRequireDefault')
exports.__esModule = true
exports.default = void 0
var _react = _interopRequireDefault(require('react'))
var _propTypes = _interopRequireDefault(require('prop-types'))
var _utils = require('@render-props/utils')
/**
import Value from '@render-props/value'
function ValueSetter () {
return (
<Value initialValue='foo'>
{({setValue, clearValue, resetValue, value}) => (
<>
<button onClick={() => setValue(value === 'foo' ? 'bar' : 'foo')}>
Change value to '{value === 'foo' ? 'bar' : 'foo'}'
</button>
<button onClick={clearValue}>
Make value 'undefined'
</button>
<button onClick={resetValue}>
Reset value to initialValue
</button>
</>
)}
</Value>
)
}
*/
function maybeSetValue(value) {
return function(prevState, props) {
if (props.value === void 0) {
let nextValue = value
if (typeof value === 'function') {
nextValue = value(prevState.value, props)
}
if (prevState.value === nextValue) {
return null
}
return {
value: nextValue,
}
}
if (process.env.NODE_ENV !== 'production') {
throw new Error(
"[Value] You called 'setValue', 'resetValue' or 'clearValue' on a " +
"controlled component. Did you mean to set 'initialValue' instead of " +
"'value'?"
)
}
return null
}
}
class Value extends _react.default.Component {
constructor(props) {
super(props)
this.setValue = value => this.setState(maybeSetValue(value))
this.resetValue = () =>
this.setState(maybeSetValue(this.props.initialValue))
this.clearValue = () => this.setState(maybeSetValue(void 0))
this.state = {
value: props.value === void 0 ? props.initialValue : props.value,
}
this.valueContext = {
setValue: this.setValue,
resetValue: this.resetValue,
clearValue: this.clearValue,
}
}
componentDidUpdate(_, {value}) {
if (value !== this.state.value) {
;(0, _utils.callIfExists)(this.props.onChange, this.state.value)
}
if (this.props.value !== void 0 && this.props.value !== this.state.value) {
this.setState({
value: this.props.value,
})
}
}
render() {
this.valueContext.value = this.state.value
/** value, setValue, resetValue, clearValue */
return this.props.children(this.valueContext)
}
}
exports.default = Value
Value.propTypes = {
children: _propTypes.default.func.isRequired,
initialValue: _propTypes.default.any,
value: _propTypes.default.any,
onChange: _propTypes.default.func,
}