» » » Топ 5 ошибок в моих ReactJS приложениях

 

Топ 5 ошибок в моих ReactJS приложениях

Автор: admin от 6-08-2019, 15:15, посмотрело: 403

Больше 4х лет назад я влюбился в ReactJS и с тех пор все Fron End приложения разрабатываю при помощи этого замечательного инструмента. За это время я и команды, в которых мне повезло поработать, наделали кучу ошибок, многие из которых были благополучно исправлены. Множество оптимальных решений было найдено в тяжелых и дорогостоящих экспериментах.



Сегодня я хочу поделиться наиболее критичными и болезненными ошибками, которые допускают чаще других. Перед написанием этой статьи, я, конечно же, проштудировал интернет в поисках похожих статей, и с удивлением обнаружил, что большинство из них устарели и рассказывают о вещах, которые мало актуальны в 2019-м году. Так что, я постарался собрать список самый актуальных проблем на текущий момент.



Топ 5 ошибок в моих ReactJS приложениях



1. Stateful компоненты (классы) хуже hook-ов



это замечательное видео Дена Абрамова, но я просто не мог начать эту статью иначе



Это, конечно, не ошибка сама по себе, но подход классов по сравнению с хуками гораздо более подвержен ошибкам, о чем уже написано немало статей:




  • Самые распространенные ошибки в вашем React коде, которые вы (возможно) делаете

  • The 7 Most Common Mistakes that React Developers Make



  • 2. Использование анонимных функций в качестве props



    Если первая ошибка еще может быть воспринята, как дань моде, то знание второй, уверяю, спасет от бессонных ночей и головной боли. Ведь именно она заставялет приложение работать настолько неадекватно, что его пользователи могут навсегда разочароваться в ReactJS. А мы ведь хотим, чтоб пользователи его любили, так же, как и мы с вами, правда? Для избежания этой ошибки можно пользоваться очень простым правилом — никогда, НИКОГДА не передавать в качестве пропса компоненту анонимную функцию.



    export default function MyOtherComponent() {
      return (
        <MyComponent getValue={i => i.value} /> {/* НИКОГДА не пишите так */}
      );
    }
    

    Более изощренный вариант этой ошибки может выглядеть как-то так (не читайте, если не знакомы с Redux):

    import { connect } from 'react-redux';
    import { createStructuredSelector } from 'reselect';
    import MyComponent from './MyComponent';
    import { fetchProjectData, projectId } from "./store/projects"
    
    const mapStateToProps = createStructuredSelector({
      projectId,
    });
    
    const mapDispatchToProps = {
      fetchProjectData,
    };
    
    const mergeProps = (
      { projectId, ...restState }: any,
      { fetchProjectData, ...restDispatch }: any,
      { memberId, ...restOwn }: any
    ) => ({
      ...restState,
      ...restDispatch,
      ...restOwn,
      fetchProjectData: () => fetchProjectData(projectId),
    });
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps,
      mergeProps
    )(MyComponent);
    

    В обоих вариантах, в конечно итоге, в props компонента попадает анонимная функция. Это плохо потому, что при каждом рендере родительского элемента, эта фукнция будет ссылаться на новый объект в памяти, а, значит, не будет равна сама себе предыдущей, и ваш компонент благополучно будет перерендерен без надобности. Это так сильно может тормозить производительность вашего приложения, что вы сами начнете плеваться и разочаровываться в React, но все дело в АНОНИМНЫХ ФУНКЦИЯХ в props-ах. Просто не делайте так никогда — и будьте счастливы.

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

    Еще пара слов, как же написать правильно. Вот как:

    const getValue = i => i.value;
    
    return default function MyOtherComponent() {
      return (
        <MyComponent getValue={getValue} />
      );
    }
    

    import { connect } from 'react-redux';
    import { createStructuredSelector } from 'reselect';
    import MyComponent from './MyComponent';
    import { fetchProjectData, projectId } from "./store/projects"
    
    const mapStateToProps = createStructuredSelector({
      projectId,
    });
    
    const mapDispatchToProps = {
      fetchProjectData,
    };
    
    export default connect(
      mapStateToProps,
      mapDispatchToProps
    )(MyComponent);
    
    // и далее в компоненте
    import React, { useEffect } from 'react';
    
    export default function MyComponent({ fetchProjectData, projectId }) {
      useEffect(() => {
        fetchProjectData(projectId);
      }, [fetchProjectData, projectId]);
    
      return (
        <div>{/* Какой-то компонент здесь*/}</div>
      );
    }
    
    // код выше можно целиком записать при помощи хуков, но я не стал приводить этот пример, т.к. считаю его так же проблемным. Возможно, когда-то я напишу почему, но не в этой статье.
    

    3. Несколько экземпляров React в приложении


    Эта ошибка, скорее, относится к архитектуре всего приложения в целом, а не только ReactJS в частности. Но эта практическая проблема очень часто стоИт перед разработчиками и слишком часто стОит им бессонных ночей.

    Пожалуйста, не пытайтесь запихнуть на одну страницу больше одного экземпляра React приложения. На самом деле, в документации React нет запрета на такой подход, я даже встречал рекомендации поступать именно так в некоторых статьях (и, конечно же, сам делал в своих приложениях подобное), НО оптимизация такого подхода и согласование всех частей приложения, в этом случае начинает занимать больше половины всего рабочего времени. Этого легко можно избежать: например, если вам нужно реагировать на какие-то события в legacy коде в вашем новом React-приложении, — вы можете использовать событийную модель. Например вот так:

    import React, { useCallback, useEffect } from 'react';
    export default function MyComponent() {
      const reactHandlerOfLegacyEvent = useCallback((event) => {/* event handler */}, []);
      
      useEffect(() => {
        document.addEventListener("myLegacyEvent", reactHandlerOfLegacyEvent);
        return () => {
          document.removeEventListener("myLegacyEvent", reactHandlerOfLegacyEvent);
        };
      }, [reactHandlerOfLegacyEvent]);
    
      return ({/* здесь какой-то компонент */});
    }
    


    4. Написание собственных библиотек, вместо существующих с открытым исходным кодом



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



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



    5. Боязнь использовать чужой код



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



    Но я так же научился понимать других разработчиков, их мысли и проблемы, с которыми они столкнулись. Видеть количество времени и сил, которые были потрачены (и не зра) на решение проблем. В 3х случаях из 5-ти, когда я берусь «улучшийть» чужой код — у меня в результате получается почти то же самое, что и было. Просто потому что на старте задачи ты, обычно, не видишь всех проблем, которые подстерегают тебя в будущем. Так что, сейчас я уважаю чужой код, каким бы странным и «устаревшим» он мне не казался. Что и вам советую.



    Спасибо



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



    Пишите о проблемах, с которыми сталкивались вы в комментариях. Возможно, у вас есть решения описанных в этой статье проблем, которые я упустил (уверен, что это так). Всем успехов и хорошего настроения!

    Источник: Хабр / Интересные публикации

    Категория: Linux

    Уважаемый посетитель, Вы зашли на сайт как незарегистрированный пользователь.
    Мы рекомендуем Вам зарегистрироваться либо войти на сайт под своим именем.

    Добавление комментария

    Имя:*
    E-Mail:
    Комментарий:
    Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
    Введите два слова, показанных на изображении: *