Enveloppez un composant de réact contrôlé, pour permettre à l'omission des paires d'accessoires / gestionnaires spécifiques d'être omises par les consommateurs de composants. Incontrollable vous permet d'écrire des composants React, avec un état minimal, puis de les envelopper dans un composant qui gérera l'état pour les accessoires / gestionnaires s'ils sont exclus.
npm i -S uncontrollable
Si vous êtes un peu incertain sur le pourquoi de ce module, lisez d'abord la section suivante. Si vous voulez juste voir des exemples du monde réel, consultez les widgets React qui font de forte usage de cette stratégie.
import { uncontrollable } from 'uncontrollable' ;
useUncontrolledProp(value, defaultValue, onChange) => [value, onChange]
Un crochet React qui peut être utilisé à la place du composant d'ordre supérieur ci-dessus. Il renvoie un ensemble complet d' props
qui sont sûrs à se propager à un élément enfant.
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
Un crochet React qui peut être utilisé à la place du composant d'ordre supérieur ci-dessus. Il renvoie un ensemble complet d' props
qui sont sûrs à se propager à un élément enfant.
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 } / > ;
} ;
L'une des forces de React est son modèle d'extensibilité, activé par une pratique courante de pousser l'état des composants aussi haut que possible l'arbre. Bien que idéal pour permettre une raison extrêmement flexible et facile à raisonner sur les composants, cela peut produire beaucoup de fonctionnalités pour les composants avec chaque utilisation. Pour les composants simples (comme une entrée), il s'agit généralement de lier le value
d'entrée à une propriété d'état parent via son gestionnaire onChange
. Voici un modèle extrêmement courant:
render ( ) {
return (
< input type = 'text'
value = { this . state . value }
onChange = { e => this . setState ( { value : e . target . value } ) }
/ >
)
}
Ce modèle éloigne la responsabilité de gérer la value
de l'entrée à son parent et imite la données "bidirectionnelle". Parfois, cependant, le parent n'est pas nécessaire de gérer directement l'état de l'entrée. Dans ce cas, tout ce que nous voulons faire est de définir la value
initiale de l'entrée et de laisser l'entrée la gérer à partir de là. React s'occupe de ceci à travers des entrées "non contrôlées", où si vous n'indiquez pas que vous souhaitez contrôler l'état de l'entrée en externe via un accessoire value
, il fera simplement la comptabilité pour vous.
C'est un excellent modèle que nous pouvons utiliser dans nos propres composants. Il est souvent préférable de construire chaque composant pour être aussi apatride que possible, en supposant que le parent voudra contrôler tout ce qui a du sens. Prenez un simple composant déroulant comme exemple
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 >
) ;
}
}
Remarquez comment nous ne suivons aucun état dans notre simple liste déroulante? C'est génial car un consommateur de notre module aura toute la flexibilité pour décider quel devrait être le comportement de la liste déroulante. Remarquez également notre API publique (Propypes), il se compose d'un modèle commun: une propriété que nous voulons définir ( value
, open
) et un ensemble de gestionnaires qui indiquent quand nous voulons qu'ils soient défini ( onChange
, onToggle
). Il appartient au composant parent de modifier la value
et open
les accessoires en réponse aux gestionnaires.
Bien que ce modèle offre une excellente quantité de flexibilité aux consommateurs, il les oblige également à écrire un tas de code de passe-partout qui ne changera probablement pas beaucoup d'utilisation. Selon toute vraisemblance, ils voudront toujours open
en réponse à onToggle
, et seuls dans de rares cas voudront remplacer ce comportement. C'est là que le modèle contrôlé / incontrôlé entre en jeu.
Nous voulons simplement gérer nous-mêmes le cas ouvert / ouverts si le consommateur ne fournit pas un accessoire open
(indiquant qu'il veut le contrôler). Plutôt que de compliquer notre composant déroulant avec toute cette logique, obscurcissant la logique métier de notre liste déroulante, nous pouvons l'ajouter plus tard, en prenant notre liste déroulante et en la terminant dans un autre composant qui gère cela pour nous.
uncontrollable
vous permet de séparer la logique nécessaire pour créer des entrées contrôlées / incontrôlées vous permettant de vous concentrer sur la création d'une entrée complètement contrôlée et l'enveloppe plus tard. Cela a tendance à être beaucoup plus simple à raisonner.
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)!
Maintenant, nous n'avons plus besoin de nous soucier de l'Open Ontoggle! Le composant renvoyé suivra open
pour nous en supposant qu'il devrait simplement open
sur tout retour onToggle
. Si nous voulons nous en inquiéter, nous pouvons simplement fournir des accessoires open
et onToggle
et l'entrée incontrôlée ne fera que les passer.
Ce qui précède est un exemple artificiel, mais il vous permet d'envelopper des composants encore plus complexes, vous donnant beaucoup de flexibilité dans l'API que vous pouvez offrir un consommateur de votre composant. Pour chaque paire de gestionnaires, vous obtenez également une valeur par défaut du formulaire "par défaut [propName]" donc value
-> defaultValue
, et open
-> defaultOpen
, etc. React Widgets fait un usage intensif de cette stratégie, vous pouvez le voir en action Ici: https://github.com/jquense/react-widgets/blob/5d1b530cb094cdc72f577fe01abe4a02dd265400/src/multiselect.jsx#l521