React中使用useState()導致的問題記錄

場景一: 更新 state 的一個對象(或數(shù)組)屬性的某個子屬性或值筛欢。

使用 Hook Function Component

function App() {
    const [arr, updateArr] = useState([]);
    const addList = () => {
        arr.push('Hello React');
        updateArr(arr);
    };
    return (
        <div>
            {
                arr.map((item, index) => (
                    <p key={index}>{index} {item}</p>
                ))
            }
            <button onClick={addList}>添加List</button>
        </div> 
    );
}

使用 Class Component

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            arr: []
        }
    }

    addList = () => {
        let arr = this.state.arr;
        arr.push('Hello React');
        this.setState({
            arr: arr
        }, () => {
            console.log(this.state.arr);
        });
    };

    deleteList = () => {
        const { arr } = this.state;
        arr.splice(0, 1);
        this.setState({
            arr: arr
        }, () => {
            console.log(this.state.arr);
        });
    };

    render() {
        const { arr } = this.state;
        return (
            <div>
                {
                    arr.map((item, index) => (
                        <p key={index}>{index} {item}</p>
                    ))
                }
            <button onClick={this.addList}>添加List</button>
            <button onClick={this.deleteList}>刪除List</button>
        </div> 
        );
    }
}

結(jié)果:使用 Hook Function Component push 數(shù)組后數(shù)組長度并沒有改變,使用Class Component正常榨咐。
原因:在 Hook 中直接修改 state 的一個對象(或數(shù)組)屬性的某個子屬性或值,然后直接進行 set谴供,不會觸發(fā)重新渲染块茁。

  • 對 Class Component來說,state 是 Immutable 的桂肌,setState 后一定會生成一個全新的 state 引用数焊。它是通過 this.state 方式讀取 state,所以每次代碼執(zhí)行都會拿到最新的 state 引用崎场。
  • 對 Hook Function Component 而言佩耳,useState 產(chǎn)生的數(shù)據(jù)也是 Immutable 的,通過數(shù)組第二個參數(shù) Set 一個新值后谭跨,原來的值會形成一個新的引用在下次渲染時干厚。

解決方案

改變引用地址

function App() {
    const [arr, updateArr] = useState([]);
    const addList = () => {
        arr.push('Hello React');
        // 通過擴展運算符實現(xiàn)深拷貝
        updateArr([...arr]);
    };
    return (
        <div>
            {
                arr.map((item, index) => (
                    <p key={index}>{index} {item}</p>
                ))
            }
            <button onClick={addList}>添加List</button>
        </div> 
    );
}

場景二: 在setTimeout中更改state。

使用 Hook Function Component

function App() {
    const [count, updateCount] = useState(0);

    useEffect(() => {
        let timer = setTimeout(() => {
            updateCount(1);
            getCount();
        }, 1000);
        return () => {
            clearTimeout(timer);
        }
    }, []);

    const getCount = () => {
        console.log(count); // result: 0
    };
    
    return (
        <div>{count}</div> 
    );
}

使用 Class Component

let timer = null;
export default class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        }
    }

   componentDidMount() {
        timer = setTimeout(() => {
            this.setState({
                count: 1
            })
            this.getCount();
        }, 1000);
   }


   getCount = () => {
        console.log(this.state.count); // result: 1
   }

   componentWillUnmount() {
        clearTimeout(timer);
   }

    render() {
        const { count } = this.state;
        console.log(count); // result: 1
        return (
            <div>{count}</div> 
        );
    }
}

結(jié)果:使用 Hook Function Component 更改count后螃宙,頁面顯示1蛮瞄,getCount方法中打印的count為0,使用Class Component更改count后頁面顯示1谆扎,getCount方法中打印的count為1挂捅。
原因:Hook Function Comoponent中由于對 state 的讀取沒有通過 this. 的方式,使得每次 setTimeout 都讀取了當時渲染閉包環(huán)境的數(shù)據(jù)堂湖,雖然最新的值跟著最新的渲染變了闲先,但舊的渲染里,狀態(tài)依然是舊值无蜂。

解決方案

使用ref

function App() {
    const [count, updateCount] = useState(0);

    useEffect(() => {
        let timer = setTimeout(() => {
            updateCount(1);
            getCount();
        }, 1000);
        return () => {
            clearTimeout(timer);
        }
    }, []);

    let ref = useRef();
    ref.current = count;
    const getCount = () => {
        console.log(ref.current); // result: 1
    };
    
    return (
        <div>{count}</div> 
    );
}

The End~

附上我認為比較值得研讀的相關文章:

1.react-hook-usestate-setState
2.精讀《Function Component 入門》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末饵蒂,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子酱讶,更是在濱河造成了極大的恐慌,老刑警劉巖彼乌,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件泻肯,死亡現(xiàn)場離奇詭異,居然都是意外死亡慰照,警方通過查閱死者的電腦和手機灶挟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來毒租,“玉大人稚铣,你說我怎么就攤上這事。” “怎么了惕医?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵耕漱,是天一觀的道長。 經(jīng)常有香客問我抬伺,道長螟够,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任峡钓,我火速辦了婚禮妓笙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘能岩。我一直安慰自己寞宫,他們只是感情好,可當我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布拉鹃。 她就那樣靜靜地躺著辈赋,像睡著了一般。 火紅的嫁衣襯著肌膚如雪毛俏。 梳的紋絲不亂的頭發(fā)上炭庙,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天,我揣著相機與錄音煌寇,去河邊找鬼焕蹄。 笑死,一個胖子當著我的面吹牛阀溶,可吹牛的內(nèi)容都是我干的腻脏。 我是一名探鬼主播,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼银锻,長吁一口氣:“原來是場噩夢啊……” “哼永品!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起击纬,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤鼎姐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后更振,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炕桨,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年肯腕,在試婚紗的時候發(fā)現(xiàn)自己被綠了献宫。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡实撒,死狀恐怖姊途,靈堂內(nèi)的尸體忽然破棺而出涉瘾,到底是詐尸還是另有隱情,我是刑警寧澤捷兰,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布立叛,位于F島的核電站,受9級特大地震影響寂殉,放射性物質(zhì)發(fā)生泄漏囚巴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一友扰、第九天 我趴在偏房一處隱蔽的房頂上張望彤叉。 院中可真熱鬧,春花似錦村怪、人聲如沸秽浇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽柬焕。三九已至,卻和暖如春梭域,著一層夾襖步出監(jiān)牢的瞬間斑举,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工病涨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留富玷,地道東北人。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓既穆,卻偏偏與公主長得像赎懦,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子幻工,可洞房花燭夜當晚...
    茶點故事閱讀 43,494評論 2 348