React性能優(yōu)化之狀態(tài)內(nèi)聚

??React 作為一個用于構(gòu)建用戶界面的 JAVASCRIPT 庫,具有高效、靈活的特性。react本身性能就很高,并且內(nèi)置了很多用于提高性能的Api,供我們使用。本文主要介紹在不借助任何Api的前提下,如何去優(yōu)化性能。下面以常見的B端列表頁面為例,并使用react-devtools-highlight-updates+gif動畫來記錄頁面的渲染范圍,來介紹如何通過狀態(tài)內(nèi)聚提高性能。話不多說,直接上代碼:

const UserInfoList: React.FC = () => {

  const [form] = Form.useForm();
  const [dataSource, setDataSource] = useState([]);
  const [cityList, setCityList] = useState([]);
  
  useEffect(() => {
    fetchDataSource();
  }, []);

  const fetCityList = (open) => {
    if (open) {
     // ... 偽代碼
     setCityList(res.data);
    }
  };

  const fetchDataSource = () => {
    // ...偽代碼
    setDataSource(res.data.list);
  };

  return (
    <div className="page-list">
      <Form form={form} onFinish={fetchDataSource}>
        <Row>
          <Col span={6}>
            <Item label="姓名" name="name"><Input/></Item>
          </Col>
          <Col span={6}>
            <Item label="年齡" name="age"> <Input/></Item>
          </Col>
          <Col span={6}>
            <Item label="城市" name="cityId">
              <Select
                options={cityList}
                onDropdownVisibleChange={fetCityList}
              />
            </Item>
          </Col>
          <Col span={6}>
            <Button type="primary" htmlType="submit">搜索</Button>
          </Col>
        </Row>
      </Form>
      <div className="table-box">
        <Table
          columns={columns}
          dataSource={dataSource}
          pagination={false}
        />
      </div>
    </div>
  );
};

export default UserInfoList;

??作為一個簡單的列表頁面,上面的代碼看起來沒啥問題,但是我們通過圖一可以看出,當(dāng)獲取城市數(shù)據(jù)并更新state時,整個頁面都重新render了,這在中大型應(yīng)用中很容易造成性能問題。

圖一

??我們對UserInfoList組件進(jìn)行優(yōu)化一下,把篩選區(qū)域提成一個單獨的組件,并且把cityList狀態(tài)從UserInfoList移動到FilterPanel中,代碼如下:

import FilterPanel from '../FilterPanel';

const UserInfoList: React.FC = () => {

  const fetchDataSource = () => {};

  return (
    <div className="page-list">
        <FilterPanel fetchDataSource={fetchDataSource} />
      <div className="table-box">
        <Table
          columns={columns}
          dataSource={dataSource}
          pagination={false}
        />
      </div>
    </div>
  );
};

export default UserInfoList;
const FilterPanel: React.FC = ({fetchDataSource}) => {
  const [form] = Form.useForm();

  const [cityList, setCityList] = useState([]);

  const fetCityList = (open) => {
    if (open) {
     // ... 偽代碼
     setCityList(res.data);
    }
  };
  
  return (
    <Form form={form} onFinish={fetchDataSource}>
      <Row>
       {/**此處省略一萬個字...*/}
        <Col span={6}>
          <Item label="城市" name="cityId">
            <Select
              options={cityList}
              onDropdownVisibleChange={fetCityList}
            />
          </Item>
        </Col>
      </Row>
    </Form>
  );
};

export default FilterPanel;

??現(xiàn)在我們再來看下圖二記錄的頁面render范圍,已經(jīng)從整個頁面,縮小到FilterPanel組件所在的篩選區(qū)域了,性能提升還是很明顯的。此時有同學(xué)可能會說,render范圍還是有點大,能不能繼續(xù)優(yōu)化呢?

圖二

??答案是肯定的,我們先來觀察一下FiltrPanel組件,cityList只有下拉組件用到了,F(xiàn)ilterPanel內(nèi)的其他代碼并沒有用到,那我們把cityList狀態(tài)繼續(xù)內(nèi)聚不就可以進(jìn)一步縮小render范圍嗎!下面我們對Select組件進(jìn)行封裝,使其變成一個相對通用的下拉組件,代碼如下:

import CusSelect from '../CusSelect'

const FilterPanel: React.FC = ({fetchDataSource}) => {
  const [form] = Form.useForm();
  return (
    <Form form={form} onFinish={fetchDataSource}>
      <Row>
       <Col span={6}>
          <Item label="城市" name="cityId">
            <CusSelect fetchOptions={getCityList}/>
          </Item>
        </Col>
      </Row>
    </Form>
  );
};

export default FilterPanel;
import React, { useState, useEffect } from 'react';
import { Select } from 'antd';

const CusSelect: React.FC = ({ fetchOptions }) => {

  const [options, setOptions] = useState([]);

  // 正常是在useEffect內(nèi)調(diào)用接口  
  // 我們在onDropdownVisibleChange函數(shù)內(nèi)部調(diào)用接口只是為了方便測試
  // useEffect(() => {
  //   fetchOptions().then(res => {
  //     setOptions(res.data);
  //   });
  // }, []);

  const getOptions = (open) => {
    if (open) {
      fetchOptions().then(res => {
        setOptions(res.data);
      });
    }
  };

  return (
    <Select options={options} onDropdownVisibleChange={getOptions}/>
  );
};

export default CusSelect;

??現(xiàn)在我們再看一下圖三記錄的頁面render范圍,已經(jīng)縮小到下拉組件所在區(qū)域了。此時我們再對比一下圖一,性能提升效果一目了然。

圖三

??總結(jié):本文通過B端常見的列表例子,介紹了如何使用狀態(tài)內(nèi)聚,來提高性能。如果組件內(nèi)狀態(tài)很多,通過狀態(tài)內(nèi)聚,能夠做到幾倍甚至幾十倍的性能提升。并且我們在做狀態(tài)內(nèi)聚的同時,還可以把原本復(fù)雜的組件,按照功能進(jìn)行拆分,這樣不僅可以提高組件的可維護(hù)性,也更加符合單一職責(zé)原則。當(dāng)然,狀態(tài)內(nèi)聚也會有一定的局限性,例如父組件或者兄弟組件依賴子組件狀態(tài),這個時候就不太適合把狀態(tài)聚合到子組件中。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • React 為高性能應(yīng)用設(shè)計提供了許多優(yōu)化方案,本文列舉了其中的一些最佳實踐。 在以下場景中,父組件和子組件通常會...
    Maco_wang閱讀 1,125評論 0 7
  • 在以下場景中,父組件和子組件通常會重新渲染:在同一組件或父組件中調(diào)用 setState 時。從父級收到的“prop...
    iien2121閱讀 647評論 0 0
  • react 性能優(yōu)化 React 組件性能優(yōu)化的核心就是減少渲染真實DOM節(jié)點的頻率,減少Virtual DOM ...
    開水泡飯閱讀 689評論 0 0
  • React 組件性能優(yōu)化最佳實踐 React 組件性能優(yōu)化的核心是減少渲染真實 DOM 節(jié)點的頻率,減少 Virt...
    JerrySi閱讀 348評論 0 0
  • 使用 React Native 替代基于 WebView 的框架來開發(fā) App 的一個強有力的理由,就是為了使 A...
    hcq666閱讀 3,126評論 0 52

友情鏈接更多精彩內(nèi)容