React組件的受控和非受控

對於組件的props和state的不一樣運用方式,形成了react組件不一樣的使用方式react

平常用到的react組件,能夠分爲以下三種瀏覽器

  1. 徹底非受控組件:沒有props,沒法從外部控制組件,修改組件的狀態
  2. 徹底受控組件:props和state徹底分開,或者乾脆沒有state
  3. 薛定諤組件:部分state會被外部傳入的props所控制,但這些state在組件內部也會被控制到,因此處在受控和非受控的中間態

如下是本身的一些理解,而且爲了方便,例子都是hooks組件,請見諒bash

徹底非受控組件

clipboard.png

// 沒有參數,傳了也不用
// 內部本身進行操做,外部沒法干涉
function Inc() {
    const [number, setNumber] = useState(0)
    
    const handleInc = () => {
        setNumber(number + 1)
    }
    
    return [
        (<p>{ number }</p>),
        (<button onClick={handleInc}>加一</button>)
    ]
}
複製代碼

這種組件通常會用在寫頁面組件,不須要進行參數的配置,全部操做都在內部ui

徹底受控組件

這類組件會把開放出來的狀態徹底交給外部控制,但不表明沒有本身內部的狀態(我理解一個組件的狀態是指的屬於它當前的props和state的集合),因此,組件徹底受控,就是state和props徹底分開,或者乾脆沒有statespa

clipboard.png

// 子組件,徹底受控
// 姓名他老子能夠控制,想讓叫什麼就叫什麼
// 年齡他老子控制不了,不能說讓他幾歲就幾歲
function Son({name}) {
    const [age, setAge] = useState(0)
    
    // @warn 若是對useEffect不太理解,這塊能夠直接理解爲age一年加一
    useEffect(() => {
        setInterval(() => {
            setAge(prevAge => prevAge + 1)
        }, 31536000000)
    }, [])
    
    return [
        (<p>兒子姓名: {name}</p>),
        (<p>兒子年齡: {age}</p>),
    ]
}

function Dad(){
    return (
        <div>
            <Son name="6牆冬">
        </div>
    )
}
複製代碼

這種纔是日常寫組件應該追求的方式,儘可能讓組件徹底受控,不會出現以下恐怖的狀況設計

薛定諤組件

這種組件是受控仍是非受控的,難說,可是這種組件很常見3d

但願您看到這尚未煩,下邊的內容纔是重點code

clipboard.png

1. 兒子示例

我要改一下上邊的Son組件,模擬如下他爸爸是瀏覽器之神,讓兒子幾歲就幾歲cdn

// 子組件,徹底受控
// 姓名他老子能夠控制,想讓叫什麼就叫什麼
// 年齡他老子也控制,說讓他幾歲就幾歲,可是兒子仍是有本身的成長
function Son({ageFromDad, name}) {
    const [age, setAge] = useState(ageFromDad)
    
    // @warn 若是對useEffect不太理解,這塊能夠直接理解爲age一年加一
    useEffect(() => {
        setInterval(() => {
            setAge(prevAge => prevAge + 1)
        }, 31536000000)
    }, [])
    
    // @warn 若是對useEffect不太理解
    // 這塊能夠直接理解爲若是傳入的ageFromDad改變,則設置age爲ageFromDad
    useEffect(() => {
        setAge(ageFromDad)
    }, [ageFromDad])
    
    return [
        (<p>兒子姓名: {name}</p>),
        (<p>兒子年齡: {age}</p>),
    ]
}

// 爸爸讓兒子一年長兩歲
function Dad(){
    const [ageFromDad, setAgeFromDad] = useState(0)
    
    // @warn 若是對useEffect不太理解,這塊能夠直接理解爲age一年加 二!!!
    useEffect(() => {
        setInterval(() => {
            setState(prevAge => prevAge + 2)
        }, 31536000000)
    }, [])
    
    return (
        <div>
            <Son name="6牆冬" age={ageFromDad}>
        </div>
    )
}
複製代碼

接下來,兒子的年齡就會出現波動,在下一年到來以前,他永遠不能肯定本身多大了blog

這個Son組件state中的age字段,出現了沒法預測的問題,就是 因爲外部和內部均可以控制其修改

2. 表單示例

這種組件用起來很難受,可是又不少不少組件都是這樣設計的

例如表單組件中Input組件,都會有一個props叫作value的屬性,這個屬性反應了當前輸入框的內容,可是操做輸入框的話也會引發value的變化,可是外部傳入的value依然是以前的值,而後組件就懵了,好吧我本身也有點懵了,以下圖

clipboard.png

這種狀況,兩個選擇: 1. 設置優先級,優先採用外部的值仍是內部的值 2. 對比,內部外部哪一個改變了用哪一個,兩個都改變,仍是優先級... 數不盡的判斷接踵而至

想着避免這種狀況

就如音樂中的和絃外音,放在和絃中感受格格不入,當彈奏的時候老是但願他向穩定的和絃中音去靠攏 物理上,但願這種中間狀態倒向一個穩定狀態

1. 徹底非受控

嗯,這是不可能的 可是能夠作成假的徹底非受控——第一次受控,之後就徹底非受控了

就是設計一個props叫作defaultValue,只在組件第一次的時候(~(羞臉)~!),能夠把外部的值傳到組件內

clipboard.png

可是這種組件,只讓控制一次,讓使用者沒有了控制慾

2. 徹底受控

仍是那個表單組件,控制一下,全部的修改都來自於外部就能夠了,內部的修改不進行value的同步

從新規劃一下數據流

  • 外部修改props.value => 內部input顯示的value
  • 內部input修改 => 通知外部同步 => 外部修改props.value => 內部input顯示的value
    這樣的話input的值永遠來自外部

實現上邊黑字的部分,就要搬出大名鼎鼎的onChange

clipboard.png

可是外部忘了作onChange的同步操做,那就會出現

clipboard.png

我的傾向仍是第二種

總結

我本身是這樣認爲的(看別的大神的文章):

讓子組件變得彈性,不要阻塞數據流 也就是說,不要把props固定到組件內部,props和state徹底分離 也就是說,讓父級組件的數據無障礙的流入子組件 也就是說,讓子組件變得徹底受控

  • 外部props => 子組件處理展現
  • 子組件出發修改 => 通知外部同步 => 外部修改props => 子組件處理展現
相關文章
相關標籤/搜索