8 СОВЕТОВ КАК СДЕЛАТЬ ВАШЕ ПРИЛОЖЕНИЕ REACT БЫСТРЕЕ.

Быстро создавать приложения легко, а вот создавать быстрые приложения гораздо сложнее. Вот несколько советов, как сделать так, чтобы ваше приложение react быстрее выводило ваши компоненты.

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

Используйте React.Memo

// неправильное применение
// без React.memo этот компонент будет выводиться каждый раз, когда
// что-то вызывает его родителя
const YourHeavyComponent = (name, title, onClick) => {

}

export default YourHeavyComponent

// правильное применение
// этот компонент не будет выводиться, пока не изменится имя, заголовок или onClick
const YourHeavyComponent = (name, title, onClick) => {
    // Рендеринг чего-то большого вроде целой страницы
}

export default React.memo(YourHeavyComponent)
Don’t have more than 4 props per component

Примеры выше демонстрируют, как вы можете легко использовать React.memo. Но иногда этого будет недостаточно для работы . Вы можете оказаться в ситуации, когда вам придется проверять некоторые компоненты, чтобы определить, будет ли он выводиться или нет.

// этот компонент не будет выводиться, пока не изменится заголовок
const YourHeavyComponent = (name, title, onClick) => {
    // Рендеринг чего-то большого вроде целой страницы
}

export default React.memo(YourHeavyComponent, (prevProps, nextProps) => {
    return prevProps.title === nextProps.title
})

Примечание: Все приведенные ниже примеры предполагают, что вы используете React.memo в своих компонентах.

Используйте минимальное количество пропсов

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

// в этом компоненте слишком много фильтров
// вместо этого нам нужно создать отдельный компонент

const List = (title, items, sortBy, keys, filters, onFilterChange, children, pagination) => {

// здесь userslist не будет выводиться, пока мы не получим новый список

const [payload, setPayload] = useState()
const [list, setList] = useState([])
return <>
    <Filters onFilterChange={setPayload} filters={payload.filters} />
    <UserList items={list}/>
    <Pagination onPaginationChange={setPayload} pagination={payload.pagination} />
</>

Используйте хук UseMemo

Используйте хук UseMemo когда у вас есть переменные, которые будут меняться после того, как что-то изменится на странице.

Пожалуйста, не забывайте, что при изменении переменных и передаче их дочерним компонентам, дочерний компонент будет отрендерен заново.

// здесь мы используем useMemo исключительно в целях кэширования, если мы не используем useMemo
// каждый раз, когда этот компонент рендерится, вычисления придется выполнять заново 
const heavyCalculated = useMemo(() => doSomeHeavyCalculation(variable1), [variable])

// пример неправильного применения
// при каждом отображении этого компонента
// переменная стилей будет указывать на разные ячейки памяти
// и это вызовет перерисовку компонента YourHeavyComponent
const styles = {
  container:{
    marginLeft: left,
    marginRight: right,
    marginTop: top,
    marginBottom: bottom,
  }
}

// правильное применение useMemo
// это кэширует ваше значение, и его точка памяти не изменится
// поэтому даже если этот компонент будет выведен, ваш компонент YourHeavyComponent
// не будет выводиться снова
const styles = useMemo(() => ({
  container:{
    marginLeft: left,
    marginRight: right,
    marginTop: top,
    marginBottom: bottom,
  }
}), [left, right, top, bottom])

Используйте хук useCallback

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

// неправильное применение
// каждый раз, когда компоненты App рендерятся по какой-либо причине
// onClickCallback будет создан заново и будет указывать на другую ячейку в памяти
// поэтому это приведет к повторному рендерингу YourHeavyComponent
const onClickCallback = () => {
  // do some stuff
}

return <div>
  <YourHeavyComponent onClick={onClickCallback} />
</div>

// правильное использование of onClickCallback
// onClickCallback будет указывать на ту же точку памяти
// поэтому UourHeavyCallback не будет Рендериться
const onClickCallback = () => {
}

return <div>
  <YourHeavyComponent onClick={onClickCallback} />
</div>

Используйте хук useRef

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


//ссылка используется для проверки, отправили ли мы это сообщение раньше или нет
sent.current
const sent = useRef(false)
const postMessage = useCallback(() => {
  if (!sent.current) {
    // здесь ваш вызов api
    sent.current = true
  }
}, [])

Не используйте встроенные массивы, объекты и функции

Никогда не забывайте, что при каждом обновлении компонентов переменные будут указывать на разные адреса памяти. Когда речь идет о примитивных типах, таких как строка и целое число, с этим проблем не будет- но если вы работаете с массивами, объектами и функциями (потому что каждая функция на самом деле является объектом если разобраться) – дело другое. Давайте посмотрим несколько примеров

const InlineTest = () => {
    // код ниже приведет к рендерингу компонента YourHeavyComponent, если
    // что-то вызывает отрисовку компонента InlineTest
    return <YourHeavyComponent style={{
        marginLeft: 10,
        marginRight: 10
    }} />
}

const InlineTest = () => {
    // код ниже  приведет к рендерингу компонента YourHeavyComponent, если
    // что-то вызывает рендеринг компонента InlineTest
    // потому что onClick будет назначаться новой функции каждый раз
    return <YourHeavyComponent onClick={() => {
        console.log('clicked');
    }} />;
}

import {useCallback} from "react";

const InlineTest = () => {
    // ниже приведён правильный метод
    // использование useCallback позволит убедиться, что функция onClick
    // будет одинаковой между обновлением и не вызовет обновления в компоненте ниже
   
    const onClick = useCallback(() => {
        console.log('clicked');
    }, [])
    return <YourHeavyComponent onClick={onClick} />;
}

Используйте оптимизированную библиотеку для работы с формами

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

import { useForm } from “react-hook-form”;

export default function App() {
  const { register, handleSubmit, formState: { errors } } = useForm();
  const onSubmit = data => console.log(data);


  return (
    /* “handleSubmit” валидирует ваш ввод перед тем как вызвать “onSubmit” */
    <form onSubmit={handleSubmit(onSubmit)}>
      {/* зарегистрируйте свой вход в хук, вызвав функцию “register” */}
      <input defaultValue=”test” {…register(“example”)} />
     
      {/* включает валидацию с помощью обязательных или иных стандартных правил валидации HTML */}
      <input {…register(“exampleRequired”, { required: true })} />
      {/* вернёт ошибку, если валидация поля не прошла  */}
      {errors.exampleRequired && <span>This field is required</span>}
     
      <input type=”submit” />
    </form>
  );
}

Будьте осторожны с Redux

В react-redux появился useSelector. Мы все можем согласиться с тем, что он облегчил нам жизнь. Но, как и все хорошее, если вы не будете осторожны, он может нанести огромный вред.

Выбирайте как можно меньше точек данных

При использовании React redux вам необходимо убедиться что ваш useSelector указывает на минимальные данные. Каждый раз, когда что-то меняется в вашем состоянии redux, будут вызваны ваши селекторы, и если они подписаны на несвязанные данные, которые вы не будете использовать, вы вызовете ненужную повторный рендеринг. Давайте рассмотрим несколько демонстраций.

const user = useSelector((state) => state.user)

<div>{user.username}</div>

Пример выше извлекает пользователя из объекта user в состоянии redux, но неправильным здесь является то, что мы подписываемся на все объекты user, хотя у нас будет только одно имя пользователя. Это означает, что даже если вы измените 'profilePicture' в любом месте нашего приложения, этот компонент будет рендериться. Давайте исправим это.

const username = useSelector((state) => state.user.username)

<div>{username}</div>

+1
0
+1
0
+1
0
+1
0
+1
0

Ответить

Ваш адрес email не будет опубликован. Обязательные поля помечены *