包裝受控的反應組件,以允許組件消費者省略特定的Prop/處理程序對。不可控制的使您可以以最小的狀態編寫React組件,然後將它們包裹在組件中,該組件將在排除prop/handler的情況下管理狀態。
npm i -S uncontrollable
如果您對此模塊的原因有些不確定,請先閱讀下一節。如果您只想看到一些現實世界的示例,請查看React小部件,以大量使用此策略。
import { uncontrollable } from 'uncontrollable' ;
useUncontrolledProp(value, defaultValue, onChange) => [value, onChange]
可以用來代替上述高階組件的React鉤子。它返回了一套完整的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
可以用來代替上述高階組件的React鉤子。它返回了一套完整的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的優勢之一是其可擴展性模型,這是通過將組件狀態盡可能高地推到樹上的共同實踐來實現的。雖然非常適合使組件非常靈活且易於推理,但它可以產生大量的樣板,以使每次使用時將組件連接起來。對於簡單的組件(例如輸入),這通常是通過其onChange
處理程序將輸入value
支架與父狀態屬性聯繫起來的問題。這是一個極為普遍的模式:
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
道具。
儘管這種模式為消費者提供了極好的靈活性,但它還要求他們編寫一堆樣板代碼,這些代碼可能不會因使用而變化太大。他們很可能總是想對onToggle
進行open
,並且只有在極少數情況下,才能覆蓋該行為。這是受控/不受控制的模式進出的地方。
如果消費者不提供open
道具(表明他們想控制它),我們只想自己處理開放/onToggle案例。我們可以通過將下拉列表和包裝在另一個為我們處理的組件中包裝,而不是使我們的下拉組件與所有邏輯造成所有邏輯的複雜性,而是掩蓋了我們的下拉邏輯。
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)!
現在,我們不需要擔心開放的Ontoggle!返回的組件將通過假設應將其open
到任何onToggle
返回的情況下為我們跟踪open
。如果我們想擔心它,我們可以提供open
和onToggle
道具,而未控制的輸入只會通過它們。
以上是一個人為的示例,但它使您可以包裝更複雜的組件,從而為您提供了很多靈活性,可以為您提供組件的消費者。對於每對Prop/處理程序,您還會獲得“默認[PREPNAME]”表單的默認設備,因此value
- > defaultValue
和open
> defaultOpen
等。react Widgets大量使用此策略,您可以在操作中看到它這裡:https://github.com/jquense/react-widgets/blob/5D1B530CB094CDC72F577FE01ABE4A02DD265400/src/src/multiselect.jsx#l521