React.memo: использование настраиваемой функции для сравнения свойств компонентов React с гибкостью и эффективностью - PullRequest
0 голосов
/ 01 мая 2020

сегодня я понял, что я передавал объект между моими компонентами React, и он создавал два нежелательных эффекта: 1 - прослушивающий его useEffect срабатывал при каждом повторном рендеринге. 2- Конечно, было много повторных рендеров.

Итак, я попытался решить, сначала используя настраиваемый пользовательский эффект, который глубоко сравнивал объект:

use-deep-Compare-effect

Кстати, он прекрасно работал благодаря kentcddodds для этого ресурса.

Но это патч для решения проблемы, которая не работает в моем коде. Итак, я начал проверять React.memo и как сравнивать мои nextProps в функциональном компоненте. Я видел много функций в сети, но ни одна не предлагала гибкость для использования с каждым компонентом и выбора способа сравнения каждого реквизита.

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

import deepEqual from 'deep-equal';
import { pick } from 'lodash';

/** Get difference between two arrays
 * @param  {} a1
 * @param  {} a2
 */
const getDiffArrays = (a1, a2) => {
    const a = [];
    const diff = [];

    for (let i = 0; i < a1.length; i++) {
        a[a1[i]] = true;
    }

    for (let i = 0; i < a2.length; i++) {
        if (a[a2[i]]) {
            delete a[a2[i]];
        } else {
            a[a2[i]] = true;
        }
    }

    for (const k in a) {
        diff.push(k);
    }

    return diff;
};

/**
 *  Return array with unique elements.
 *  ! How efficient is it? This is a function that is intensively used. Get
 * @param  {} arr
 */
const getDistinctKeysArray = (obj1, obj2) => [
    ...new Set([...Object.keys(obj1), ...Object.keys(obj2)]),
];

const compare = (obj1, obj2, compareFunc) => {
    let res = true;
    const keys = Object.keys(obj1);
    for (let key = 0; res && res < keys.length; key++) {
        res = compareFunc(obj1[keys[key]], obj2[keys[key]]);
    }
    return res;
};

/**
 * Shallow comparison
 *
 * @param  {} obj1
 * @param  {} obj2
 */
const compareShallow = (obj1, obj2) => obj1 === obj2;

/**
 * Fast object comparison. It use JSON.stringfy. The problem is that is the order of the props change it
 * will return false, between others
 * @param  {} obj1
 * @param  {} obj2
 */
const compareFastDeep = (obj1, obj2) =>
    JSON.stringify(obj1) === JSON.stringify(obj2);
/**
 *  Function to compare object with flexibility.
 * @param  {} obj1
 * @param  {} obj2
 * @param  {} keysCompareFullDeep array keys that are going to be compare using a full deep method that is slowers but effective
 * @param  {} keysCompareFastDeep array keys that are going to be compare using a fast deep method that is not fully effective
 */
const compareHelper = (
    prevProps,
    nextProps,
    keysCompareFullDeep = [],
    keysCompareFastDeep = []
) => {
    // Get keys for shallow compare
    const keysCompareShallow = getDiffArrays(
        getDistinctKeysArray(Object.keys(prevProps), Object.keys(nextProps)),
        getDistinctKeysArray(keysCompareFastDeep, keysCompareFullDeep)
    );
    console.log(keysCompareShallow);
    // Compare shallow
    let res = compare(
        pick(prevProps, keysCompareShallow),
        pick(nextProps, keysCompareShallow),
        compareShallow
    );
    console.log(res);

    // Compare deep fast
    res = res
        ? compareFastDeep(
              pick(prevProps, keysCompareFastDeep),
              pick(nextProps, keysCompareFastDeep)
          )
        : res;
    console.log(res);

    // Compare deep full
    res = res
        ? deepEqual(
              pick(prevProps, keysCompareFullDeep),
              pick(nextProps, keysCompareFullDeep)
          )
        : res;
    console.log(res);
    return res;
};

export { compareHelper };

И использование:

SearcherComponent.propTypes = {
    cars: PropTypes.array.isRequired,
    filters: PropTypes.object.isRequired,
    mainFilters: PropTypes.array.isRequired,
    options: PropTypes.object.isRequired,
    onFilterChange: PropTypes.func.isRequired,
    onFilterDelete: PropTypes.func.isRequired,
    onShowMoreFilters: PropTypes.func.isRequired,
    showMoreFilters: PropTypes.bool.isRequired,
    addToFavorite: PropTypes.func.isRequired,
    deleteFavorite: PropTypes.func.isRequired,
    onSaveFilterList: PropTypes.func.isRequired,
    cleanFilterList: PropTypes.func,
    chatRequest: PropTypes.func.isRequired,
    goToCarExtendedInfo: PropTypes.func,
    pagination: PropTypes.shape({
        loading: PropTypes.bool,
        setPaginationInfo: PropTypes.func,
        sortBy: PropTypes.object.isRequired,
        setSortBy: PropTypes.func.isRequired,
        pagination: PropTypes.object,
    }),
    children: PropTypes.node.isRequired,
};
const Searcher = React.memo(SearcherComponent, (prev, next) =>
    compareHelper(prev, next, ['pagination', 'cars', 'filters'], [])
);
export { Searcher as SearcherComponent };

Я знаю, что код немного запутан, я тестирую несколько реализаций.

Если мы получим хороший В порядке эффективности я планирую создать пакет publi c npm.

Пожалуйста, если кто-нибудь знает, имеет ли это смысл и как сделать это быстрее, скажите мне. При рассмотрении вопроса об изменении глубокий-равный на быстрый-глубокий-равный

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...