оптимизация производительности react/react-native

React.js React Native

написать впереди

Эта статья подходит для новичков, если вы старый игрок в React, вы можетеbreakИли проверить на пропуски.


Вот некоторые распространенные ошибки новичков и методы оптимизации:

Почему вам нужно оптимизировать

Я всегда считал, что оптимизация производительности — это кумулятивный процесс, который проходит через каждую строчку кода, который вы пишете. Если не обращать внимания на оптимизацию, то это может и не быть большой проблемой, но никто не знает, какое предложение станет той соломинкой, которая сломает хребет верблюду и заставит мир взорваться💥.


Ниже приведен текст, я надеюсь, что он может вам помочь.

Фокус оптимизации React

Ядро оптимизации производительности реагирования:

Уменьшите количество рендеров! отложить или амортизировать рендер

Причина в том, что большая часть накладных расходов на реакцию генерируется в период рендеринга, в процессе рендеринга будет много копирования объектов, и в то же время будет сгенерировано много фрагментированных объектов (элементов реакции), которые используется для сравнения с предыдущим объектом и каждый раз генерируется при рендеринге.

Ввиду этой особенности, некоторые часто используемые методы оптимизации резюмируются:

Пример оптимизации

  1. согласно сpropsМодуль инициализации

пример:

    class Page extends Component (props) {
        state = {
            a: 1
        }
        componentDidMount() {
            this.setState({
                a: this.props.a
            })
        }
    }

Очевидная ошибка — модифицировать компонент дважды в жизненном цикле, хотя это соответствует времени модификации состояния (componentDidMountВнутреннее измененное состояние), но вы должны подумать о том, есть ли подозрение на избыточное вторичное рендеринг, это должно быть непосредственноconstructorвнутренняя инициализация (также больше соответствует буквальному определению «инициализации»).

оптимизация:

class Page extends Component (props) {
        constructor(props) {
            super(props)
            this.state = {
                a: props.a
            }
        }
    }
  1. наследоватьPureComponent

пример:

    class Page extends Component (props) {
        constructor(props) {
            super(props)
            this.state = {
                a: props.a
            }
        }
    }

ТамpropsПриходит и не используетсяshouldComponentUpdateиспользовать в случаеPureComponentможет эффективно уменьшитьrenderколичество раз, которое по существу использует компонентshouldComponentUpdate(newProps, newState)жизненный цикл, вrenderСравнить доprops、 state(поверхностное сравнение), если изменений нет, то и обновляться не будет.

оптимизация:

class Page extends PureComponent (props) {
        constructor(props) {
            super(props)
            this.state = {
                a: props.a
            }
        }
    }
  1. использоватьshouldComponentUpdate

пример:

    class Page extends Component (props) {
        constructor(props) {
            super(props)
            const { a, b } = props.data;
            this.state = {
                a,
                b
            }
        }
        render() {
            const { a } = this.props.data;
            return <div>{a}</div>
        }
    }

На протяженииrenderнужно толькоaне используется в случаеshouldComponentUpdate, а обновления компонентов обычно проходят в новом объекте, еслиaзначение не изменилось, что привело бы к бессмысленномуrerender.

оптимизация:

    class Page extends Component (props) {
        constructor(props) {
            super(props)
            const { a, b } = props.data;
            this.state = {
                a,
                b
            }
        }
        shouldComponentUpdate(newProps, newState) {
            if (newProps.data.a !== this.props.data.a) {
                return true;
            }
            return false;
        }
        render() {
            const { a } = this.props.data;
            return <div>{a}</div>
        }
    }
  1. Разумное разделение компонентов для сложных страниц

пример:

    class Page extends PureComponent (props) {
        constructor(props) {
            super(props)
            this.state = {
                a: 1,
                ...
            }
        }
        render() {
            const { a } = this.props.data;
            return <div>
                {...}
            </div>
        }
    }

реагироватьdiffСравнение ведется в единицах компонентов.Страница тоже большой компонент.Все данные находятся на одной странице,и любое изменение состояния приведет к обновлению всей страницы. Разумно разделить компоненты и объединитьPureComponentОпределение компонентов может сократить количество рендерингов неизмененных частей страницы и в то же времяdiffСтепень детализации сравнения выше.

оптимизация:

    class Page extends PureComponent (props) {
        constructor(props) {
            super(props)
            this.state = {
                a: 1,
                b: 2
            }
        }
        render() {
            const { a } = this.props.data;
            return <div>
                <Component1 a={a} />
                <Component2 b={b} />
                ...
            </div>
        }
    }
  1. существуетcomponentDidMountПериодически вызывайте интерфейс и возвращайтесь послеsetState(Как напомнили друзья в области комментариев, поскольку componentWillMount react16.3 был помечен как небезопасный жизненный цикл, он будет удален в 17, поэтому эта статья больше не рекомендуется, спасибо @Flasco напоминание)

пример:

    class Page extends PureComponent (props) {
        constructor(props) {
            this.state = {
                a: 1
            }
        }
        componentDidMount() {
            this.getData()
        }
        getData async() {
            const result = await API.getData();
            this.setState({
                a: result.a
            })
        }
    }

react подчеркивает, что его нельзя использовать вcomponentWillMountИзмените состояние в , но здесь необходимо учитывать, что вызывающий интерфейс является асинхронной операцией, и все асинхронные операции на веб-стороне будут выполняться после завершения синхронной операции, поэтому в случае вызовов интерфейса или других асинхронных операции, вы можетеcomponentWillMountВызов интерфейса в обратном вызове и запись изменения состояния в обратном вызове может ускорить время отклика.

оптимизация:

    class Page extends PureComponent (props) {
        constructor(props) {
            this.state = {
                a: 1
            }
        }
        componentWillMount() {
            this.getData()
        }
        getData async() {
            const result = await API.getData();
            this.setState({
                a: result.a
            })
        }
    }
  1. Не определяйте функции в jsx

пример:

    class Page extends PureComponent (props) {
        render() {
            return (
                <div onClick={() => {
                    ...
                }}/>
            )
        }
    }

Функция, определенная в методе рендеринга, будет переопределяться при каждом обновлении компонента, и каждый раз, когда определение будет повторно применяться к блоку памяти, что приведет к увеличению использования памяти, запуск сборки мусора js также увеличит накладные расходы и серьезно повлияет на производительность. представление. Функции должны храниться в экземплярах, постоянных методах и памяти, быть привязанными или использоваться в рендеринге.

оптимизация:

    class Page extends PureComponent (props) {
        onClick = () => {
            ...
        }
        render() {
            return (
                <div onClick={this.onClick}/>
            )
        }
    }
  1. Не связывайте это в jsx

пример:

    class Page extends PureComponent (props) {
        onClick() {
            ...
        }
        render() {
            return (
                <div onClick={this.onClick.bind(this)}/>
            )
        }
    }

Хотя функция определена и сохранена в экземпляре, метод привязки вернет новую функцию, что также увеличивает использование памяти и накладные расходы на сборку мусора. Вы можете определить функцию непосредственно как функцию стрелки или использовать привязку в конструкторе, чтобы изменить ее на точку.

оптимизация:

    class Page extends PureComponent (props) {
        constructor(props) {
            super(props)
            this.state = {
                ...
            }
            this.onBindClick = this.onBindClick.bind(this)
        }
        onClick = () => {
            ...
        }
        onBindClick() {
            ...
        }
        render() {
            return (
                <div onClick={this.onClick}>
                    <div onClick={this.onBindClick}/>
                </div>
            )
        }
    }
  1. добросовестное использование ссылки

пример:

    const SLIDER_WEIGHT = 200
    class Page extends PureComponent (props) {
        constructor(props) {
            super(props)
            this.state = {
                left: 0
            }
        }
        componentDidMount() {
            this.initSwiper()
        }
        initSwiper = () => {
            this.intervalId = setInterval(() => {
                this.setState((state) => ({
                    left: left + SLIDER_WEIGHT
                })))
            }, 2000)
        }
        render() {
            const { left } = this.state
            return (
                <div>
                    <div style={{left: left + 'px'}}>
                        ...
                    </div>
                </div>
            )
        }
    }

Предположим, что здесь должна быть реализована карта карусели, и для достижения эффекта карусели она часто модифицируется в таймере цикла.state, каждый раз, когда состояние компонента обновляется, это приводит к частому отображению компонента. В настоящее время вы можете использовать ref для изменения стиля dom без запуска обновлений компонентов.

оптимизация:

пример:

    const SLIDER_WEIGHT = 200
    class Page extends PureComponent (props) {
        left = 0
        componentDidMount() {
            this.initSwiper()
        }
        initSwiper = () => {
            this.intervalId = setInterval(() => {
                this.left += SLIDER_WEIGHT
                this.refs.swiper.style.left = this.left + 'px'
            }, 2000)
        }
        render() {
            const { left } = this.state
            return (
                <div>
                    <div ref="swiper">
                        ...
                    </div>
                </div>
            )
        }
    }
  1. Использование фрагментов

пример:

    () => <div>
        <div>content1</div>
        <div>content2</div>
    </div>

Когда вы пишете отдельный компонент, если вы обнаружите, что самый внешний элемент по существу избыточен, но дочерний элемент имеет несколько тегов, которые не могут быть представлены напрямую, вы должны использовать Fragment, пустой тег jsx. Это позволит отображать на один тег меньше и сделает наш код более лаконичным.

оптимизация:

пример:

    () => <>
        <div>content1</div>
        <div>content2</div>
    </>

точки оптимизации реакции

上文中几条优化方法同样适用于react-native,因为它们有着同样的抽象层,但是react-native有一些独特的优化技巧,提供给即将需要写native的同学😏

  1. Используйте анимированные анимации для выполнения некоторых функций изначально. Можно понимать как анимацию CSS3, базовая оптимизация и более простая реализация делают меня счастливым.

  2. Подумайте, можете ли вы использовать более качественные компоненты: listView, Flatlist... и атрибуты: pagesize, removeClippedSubviews..., что также удобно благодаря базовой оптимизации.

  3. Используйте Interactionmanager, чтобы организовать трудоемкую работу после завершения всех взаимодействий или анимаций, а затем выполнить распределение накладных расходов (узкое место в производительности, вызванное взаимодействием между нативным js и нативным кодом) и выполнить обратный вызов в Interactionmanager.runAfterInteractions().


Выше приведены некоторые точки оптимизации производительности react/react-native, которые я обобщил.Если у вас есть другие решения, пожалуйста, оставьте сообщение ниже, и я добавлю его вовремя.Наконец, я желаю всем писать код без ошибок и всегда иметь лучшую производительность.

//
//                            _ooOoo_
//                           o8888888o
//                           88" . "88
//                           (| -_- |)
//                           O\  =  /O
//                        ____/`---'\____
//                      .'  \\|     |//  `.
//                     /  \\|||  :  |||//  \
//                    /  _||||| -:- |||||-  \
//                    |   | \\\  -  /// |   |
//                    | \_|  ''\---/''  |   |
//                    \  .-\__  `-`  ___/-. /
//                  ___`. .'  /--.--\  `. . __
//               ."" '<  `.___\_<|>_/___.'  >'"".
//              | | :  `- \`.;`\ _ /`;.`/ - ` : | |
//              \  \ `-.   \_ __\ /__ _/   .-` /  /
//         ======`-.____`-.___\_____/___.-`____.-'======
//                            `=---='
//        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//                      佛祖保佑       永无BUG

-- The end