Оберните контролируемый компонент React, чтобы разрешить определенные пары опоры/обработчика быть опущенными потребителями компонентов. Неконтролируемый позволяет писать компоненты React с минимальным состоянием, а затем обернуть их в компонент, который будет управлять состоянием для опоры/обработчиков, если они исключены.
npm i -S uncontrollable
Если вы немного не уверены в том, почему этого модуля сначала прочитайте следующий раздел. Если вы просто хотите увидеть некоторые примеры реального мира, посетите виджеты React, которые используют эту стратегию.
import { uncontrollable } from 'uncontrollable' ;
useUncontrolledProp(value, defaultValue, onChange) => [value, onChange]
Реагированный крючок, который можно использовать вместо вышеуказанного компонента более высокого порядка. Он возвращает полный набор props
, которые безопасны для распространения до дочернего элемента.
import { useUncontrolledProp } from 'uncontrollable' ;
const UncontrolledCombobox = ( { value , defaultValue , onChange } ) => {
// filters out defaultValue, defaultOpen and returns controlled
// versions of onChange, and onToggle.
const [ controlledValue , onControlledChange ] = useUncontrolledProp (
value ,
defaultValue ,
onChange
) ;
return < Checkbox { ... controlledProps } / > ;
} ;
useUncontrolled(props, propsHandlerHash) => controlledProps
Реагированный крючок, который можно использовать вместо вышеуказанного компонента более высокого порядка. Он возвращает полный набор props
, которые безопасны для распространения до дочернего элемента.
import { useUncontrolled } from 'uncontrollable' ;
const UncontrolledCombobox = ( props ) => {
// filters out defaultValue, defaultOpen and returns controlled
// versions of onChange, and onToggle.
const controlledProps = useUncontrolled ( props , {
value : 'onChange' ,
open : 'onToggle' ,
} ) ;
return < Checkbox { ... controlledProps } / > ;
} ;
Одной из сильных сторон React является его модель расширения, обеспечиваемая обычной практикой толкания состояния компонента как можно более высоко в дереве. Хотя это отлично подходит для того, чтобы обеспечить чрезвычайно гибкую и простую в рассуждении о компонентах, это может привести к тому, что компоненты проводятся с каждым использованием. Для простых компонентов (таких как вход) это, как правило, вопрос связывания входного value
с свойством родительского состояния через его обработчик onChange
. Вот чрезвычайно распространенная схема:
render ( ) {
return (
< input type = 'text'
value = { this . state . value }
onChange = { e => this . setState ( { value : e . target . value } ) }
/ >
)
}
Этот шаблон переносит ответственность за управление value
от ввода к своему родителю и имитирует «двустороннюю» базу данных. Иногда, однако, у родителя нет необходимости напрямую управлять состоянием ввода. В этом случае все, что мы хотим сделать, это установить начальное value
ввода и позволить вводу управлять им с тех пор. React имеет дело с этим с помощью «неконтролируемых» входов, где, если вы не указываете, что вы хотите управлять состоянием ввода внешне через value
опору, он просто сделает для вас бренер.
Это отличный шаблон, который мы можем использовать в наших собственных компонентах. Часто лучше создавать каждый компонент, чтобы быть максимально без гражданства, предполагая, что родитель захочет контролировать все, что имеет смысл. Возьмите простой выпадающий компонент в качестве примера
class SimpleDropdown extends React . Component {
static propTypes = {
value : React . PropTypes . string ,
onChange : React . PropTypes . func ,
open : React . PropTypes . bool ,
onToggle : React . PropTypes . func ,
} ;
render ( ) {
return (
< div >
< input
value = { this . props . value }
onChange = { ( e ) => this . props . onChange ( e . target . value ) }
/ >
< button onClick = { ( e ) => this . props . onToggle ( ! this . props . open ) } >
open
< / button >
{ this . props . open && (
< ul className = "open" >
< li > option 1 < / li >
< li > option 2 < / li >
< / ul >
) }
< / div >
) ;
}
}
Обратите внимание, как мы не отслеживаем какое -либо состояние в нашем простом выпадении? Это здорово, потому что потребитель нашего модуля будет иметь всю гибкость, чтобы решить, каким должно быть поведение раскрывающегося списка. Также обратите внимание на наш общественный API (Proptypes), он состоит из общего шаблона: свойство, которое мы хотим установить ( value
, open
) и набор обработчиков, которые указывают, когда мы хотим, чтобы они установили ( onChange
, onToggle
). Это зависит от родительского компонента, чтобы изменить value
и open
реквизиты в ответ на обработчиков.
Хотя этот шаблон предлагает превосходную гибкость для потребителей, он также требует, чтобы они писали кучу кода шаблона, который, вероятно, не сильно изменится от использования. По всей вероятности, они всегда захотят open
в ответ на onToggle
, и только в редких случаях захотят переопределить это поведение. Здесь появляется контролируемый/неконтролируемый шаблон.
Мы хотим просто справиться с делом Open/Ontoggle, если потребитель не предоставляет open
опору (указывая на то, что они хотят контролировать его). Вместо того, чтобы усложнять наш раскрывающий компонент со всей этой логикой, затмевая бизнес -логику нашего раскрывающегося списка, мы можем добавить его позже, взяв наш выпадающий список и завернув ее в другой компонент, который обрабатывает это для нас.
uncontrollable
позволяет разделить логику, необходимую для создания контролируемых/неконтролируемых входов, позволяющих вам сосредоточиться на создании полностью управляемого ввода и обертывания его позже. Это, как правило, намного проще рассуждать.
import { uncontrollable } from 'uncontrollable' ;
const UncontrollableDropdown = uncontrollable ( SimpleDropdown , {
value : 'onChange' ,
open : 'onToggle'
} )
< UncontrollableDropdown
value = { this . state . val } // we can still control these props if we want
onChange = { val => this . setState ( { val } ) }
defaultOpen = { true } / > // or just let the UncontrollableDropdown handle it
// and we just set an initial value (or leave it out completely)!
Теперь нам не нужно беспокоиться об открытом онтоггле! Возвращенный компонент будет open
для нас, предполагая, что он должен просто open
для того, что возвращает onToggle
. Если мы хотим беспокоиться об этом, мы можем просто предоставить open
и onToggle
реквизит, и неконтролируемый вход просто пройдет их.
Выше приведенное пример, но он позволяет вам обернуть еще более сложные компоненты, что дает вам большую гибкость в API, вы можете предложить потребителю вашего компонента. Для каждой пары Prop/Handlers вы также получаете defaultprop формы «default [propname]», так что value
-> defaultValue
и open
-> defaultOpen
и т. Д. React Widgets использует эту стратегию, вы можете увидеть ее в действии Здесь: https://github.com/jquense/react-widgets/blob/5d1b530cb094cdc72f577fe01abe4a02dd265400/src/multiselect.jsx#l521