Ответы пользователя по тегу React
  • Как поменять через React-код background-image в зависимости от условия if-else?

    Aetae
    @Aetae
    Тлен
    Во-первых: зачем ты лезешь в dom руками через ref? Пиши в state и используя значение в свойстве style компонента. Или даже не в state а тупо в переменную.

    Во-вторых: чтобы сборщик обработал картинку из хрен пойми откуда - надо её импортировать через import и уже потом подставлять результат.
    Однако если картинка лежит в public, это не обязательно, можно прям на неё ссылаться от корня. Только посмотри где она действительно лежит: если лежит в /public/img/morning.jpg, то писать надо соответственно '/img/morning.jpg без всяких assets и наоборот.
    Ответ написан
    Комментировать
  • Как в react-router-dom сделать чтобы loader не блокировал рендер страницы?

    Aetae
    @Aetae
    Тлен
    Сам не пользовался, но по докам вроде никаких магических параметров не вижу.

    Вот тебе тогда вспомогательные функции которые сделают то, что тебе надо:
    import { json, useLoaderData } from "react-router-dom";
    import { useEffect } from "react";
    
    export function eagerLoader(loader) {
      return (...args) => {
        const promise = loader(...args)
          .then(res => res instanceof Response ? res.json() : res );
        return json({ promise }, { status: 200 });
      }
    }
    
    export function useEagerLoaderData(defaultData) {
      const [data, setData] = useState(defaultData);
      const promise = useLoaderData()?.promise;
    
      useEffect(() => {
        promise?.then(setData);
      }, [promise]);
    
      return data;
    }
    let route = {
      path: "...",
      loader: eagerLoader(({ request }) => ...),
      lazy: () => import("./Comp"),
    };
    
    const Comp = () => {
      const data = useEagerLoaderData([]);
    
      //...
    }

    Код не проверял, но думаю логика очевидна.:)

    P.S. defaultData мб стоит вынести в обёртку eagerLoader, хз, тут сам смотри свои юзкейсы.:)
    Ответ написан
    1 комментарий
  • Почему некоректно обновляется ширина в кастомном хуке?

    Aetae
    @Aetae
    Тлен
    Классика: ты этот width наверняка присваиваешь какому-то элементу. Соответственно, ширина этого элемента становится ровна width. Когда ты меняешь ориентацию - ты не убираешь width перед этим, а значит innerWidth окна не минимальное значение, а то, какое получилось с учётом элемента с width, который это окно распирает.
    Т.е. после каждого увеличения width, window.innerWidth не может быть меньше чем width.

    Такие задачи принято решать вёрсткой.
    Ответ написан
    2 комментария
  • Как сделать рендер только один раз?

    Aetae
    @Aetae
    Тлен
    Обернуть App в memo. Ток прям один раз всё равно не получится: один рендер на отображение пустых users, второй на отображение заполненных когда те загрузятся.
    Ответ написан
    Комментировать
  • Отображение содержимого pdf файла на сайте?

    Aetae
    @Aetae
    Тлен
    Можно взять pdf.js и допилить как тебе надо. Будет жирно и тяжело.
    Либо моджно сохранить pdf как набор картинок и просто положить их на сайт. Будет просто и жирно.
    Ответ написан
    4 комментария
  • Как изменить стили для message в Ant Design в React?

    Aetae
    @Aetae
    Тлен
    Судя по доке на внутренний контент props'a класса нет.
    Остаётся три варианта:
    1. Изменение темы:
    В v4 глобально, изменив less переменную: @message-notice-content-bg, в v5 через свойство contentBg:

    https://ant.design/docs/react/migrate-less-variabl...

    2. Тупо руками переписать вложенный класс:
    .custom-class .ant-message-notice-content { ... }

    3. Передать кастомный компонент с нужными стилями в качестве content.
    Ответ написан
  • Как вложить span в textarea?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Никак.
    Textarea - зона текста, там может быть только текст.
    Если хотите большего - есть только три варианта, два - геморройные, с кучей коссбраузерных несовместимостей и особенностей, которые обязательно заставят вас рвать волосы на заднице:
    1. Отказаться от textarea и использовать contentEditable div.
    2. Подкладывать под(или поверх с pointer-events:none) div, который копирует содержимое textarea 1:1 со всеми стилями и отступами и раскрашивает его как надо.

    ...и третий, рекомендуемый лично мной:
    3. Использовать одну из долгоживущих готовых библиотек, в которых всё давно отладили и предоставили удобные интерфейсы.
    Ответ написан
    3 комментария
  • Почему не работают хуки с использованием createBrowserRouter?

    Aetae
    @Aetae
    Тлен
    Очевидно: element: UserAuth(), -> element: <UserAuth />,
    Ответ написан
  • Ошибка Failed prop type: Invalid prop `children` supplied to `ForwardRef(Box)`, expected a ReactNode. Что я делаю не так?

    Aetae
    @Aetae
    Тлен
    React так не умеет. Сам механизм react делает такое невозможным.
    Все компоненты синхронны(кроме lazy, но это совсем другое).
    Ты должен свою асинхронную функцию вызвать в useEffect, а пока она грузится показывать какой-нить лоадер.
    Ответ написан
    1 комментарий
  • Ошибка Error: Hydration failed because the initial UI does not match what was rendered on the server. Как исправить?

    Aetae
    @Aetae
    Тлен
    Очевидная проблема в том, что ты рендеришь страницу по разному в зависимости от свойств экрана юзера, однако сервер не знает ничего об юзерском экране, потому результат SSR и результат на клиенте - разный, что и вызывает ошибки гидрации.

    Красивого решения тут нет, только разные костыли, например:
    1. Первый раз рендерить компонент всегда одинаково, а потом уже обновлять по useEffect в зависимости от экрана. Простое решение которое сразу заработает, однако может привести к кратковременном миганию на клиенте при загрузке.
    1а. Вычислять по userAgent что у клиента мобила\планшет и первым рисовать наиболее вероятный вариант, а потом уже по useEffect использовать точный, если не угадали. Тоже самое но есть шанс что угадаем.
    2. Рисовать все варианты на странице, а скрывать тупо классами css не используя этой либы. Тоже сразу заработает, но на странице куча мусора.
    3. ?
    Ответ написан
    Комментировать
  • Возможно ли изменить поведение contentEditable?

    Aetae
    @Aetae
    Тлен
    Поменять поведение - нельзя.
    Отслеживать изменения и переписывать - можно, но не нужно.
    Ответ написан
    Комментировать
  • Как сделать фильтрацию?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Чтоб сделать фильтрацию просто делаешь так:
    const [selected, setSelected] = useState('all');
    
      let filterdTodos;
      switch(selected) {
        case 'all':
          filterdTodos = todos;
          break;
        case 'checked':
          filterdTodos = todos.filter(t => t.checked);
          break;
        case 'notChecked':
          filterdTodos = todos.filter(t => !t.checked);
          break;
      }

    Или так, с оптимизацией:
    const [selected, setSelected] = useState('all');
    
      const filterdTodos = useMemo(() => {
        switch(selected) {
          case 'all':
            return todos;
          case 'checked':
            return todos.filter(t => t.checked);
          case 'notChecked':
            return todos.filter(t => !t.checked);
        }
      }, [selected, todos])

    <select className="todos__filter" onChange={(event) =>setSelected(event.target.value)}>
    ...
    {filterdTodos.map(...)}
    Ответ написан
  • При сборке к имени картинок добавляется хеш и картинки не отображаются. Как указывать путь к картинкам?

    Aetae
    @Aetae
    Тлен
    React - это тебе не Vue, он не умеет из коробки угадывать, что картинки надо импортировать.

    Для каждой картинки надо сделать руками:
    import img from './assets/img.jpeg'
    или использовать glob import.

    Ну либо положить картинки в public и брать их как есть по прямым путям относительно корня без всяких хэшей.

    Подробнее.
    Ответ написан
    Комментировать
  • Как использовать один компонент с разными типами данных?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Наверное ты хочешь этого:
    type Props = { data?: ITemplate } | {}
    const CreateTemplateForm: FC<Props> = (props) => {
      if ('data' in props && props.data) {
        
        return ...;
      }
    
      return ...;
    }
    Ответ написан
    5 комментариев
  • Как запустить реакт код без локального сервера или как его получить?

    Aetae
    @Aetae
    Тлен
    Забудь о фронте без локального сервера. Это время ушло.
    Сейчас для локальных файлов столько ограничений, что работать с этим даже на чистом html уже толком невозможно.
    Ответ написан
  • Для чего мемоизируют аутентификацию?

    Aetae
    @Aetae
    Тлен
    На самом деле useMemo нужен, чтобы при передаче значения как prop в низлежащий memo компонент не происходила перерисовка оного если не было изменений(+при передаче как зависимость в другой хук, тот не срабатывал заново).
    Стоит упустить хотя-бы одно место требующее useMemo и пойдёт водопадом перерисовка на каждый чих каждого компонента по всему дереву вниз. И именно это является основной причиной тормозов в React, а не какие-то там мифические сложные вычисления.

    Официальная позиция React: "говнокодь сейчас, оптимизируй потом", действительно предполагает использование useMemo "только в узких местах" и нигде больше. Прикол в том, что с таким подходом при разрастании проекта никакого "узкого места" просто нет, тормозить начинает просто потому, что складываются тысячи микротормозов от тысяч перерисовок тысяч компонентов: наступает то самое "потом" и тут придётся переписывать с useMemo чуть ли не весь проект, чтоб снизить эти тормоза.
    Именно по этому в реальной работе useMemo стараются таки использовать заранее в каждом месте, где оно потенциально нужно. Некоторые радикальные философии вообще предполагают использование useMemo просто всегда, без исключений.:)
    Ответ написан
    3 комментария
  • Как компонент реакта понимает, что к нему привязали хук?

    Aetae
    @Aetae
    Тлен
    Простой ответ: глобальные переменные.:)
    React просто перед самим запуском устанавливает глобальную (условно) переменную указывающую на текущий исполняющийся компонент, на которую и смотрит в сою очередь хук. Именно потому хуки нельзя использовать вне компонента.
    Вот тут я упрощённо изобразил, что дальше происходит внутри useState.

    Конечно всё намного сложнее, но основная суть именно такова. Подробнее - уже в исходники.
    Ответ написан
    2 комментария
  • Как при нажатии кнопки выводить поэтапно строки которые значение увеличивается на 1?

    Aetae
    @Aetae Куратор тега JavaScript
    Тлен
    Для начала забудем о react и поговорим о javascript: javascript риусет ui в одном потоке, потому while - это атомарная операция. На экране ничего не отобразится пока while не закончит своё действие. Т.е. выведя 10 строк через while - ты сразу увидишь их на экране, они не будут появляться по одной. Если, конечно, не подключишь асинхронность с async и await внутри цикла.

    Теперь к react: отображение нескольких строк осуществляется с помощью массива:
    const lines = [1, 2, 3];
    
    return lines.map(line => (
      <p> {line} </p>
    ));


    Если ты хочешь, чтоб при клике добавлялась строчка, то состояние этого массива надо отслеживать, т.е. напримр положить его в state:
    function Component() {
      const [lines, setLines] = useState([1, 2, 3]);
      const addLine = useCallback(() => {
        setLines(lines => [...lines, lines.length+1])
      });
    
      return(
        <>
          <button onClick={addLine} className="button">
            addLine
          </button>
          {lines.map(line => (
            <p> {line} </p>
          ))}
        </>
    }


    Если ты хочешь, чтоб при клике постепенно добавлялась 10 строчек с задержкой, то это можно сделать с помощью setTimeout(тут я обернул его в Promise для простоты и наглядности):
    const delay = (ms) => new Promise(r => setTimeout(r, ms))
    
    function Component() {
      const [lines, setLines] = useState([]);
      const addLines = useCallback(async () => {
        let i = 0;
        while(i++ < 10) {
          await delay(1000);  
          setLines(lines => [...lines, i])
        }
      });
      return(
        <>
          <button onClick={addLines} className="button">
            addLine
          </button>
          {lines.map(line => (
            <p> {line} </p>
          ))}
        </>
      );
    }
    Ответ написан
    Комментировать
  • Почему при сборке библиотеки и подключения ее, выдает ошибку?

    Aetae
    @Aetae Куратор тега TypeScript
    Тлен
    Не надо ничего "копировать из dist". В node_modules должен быть модуль, т.е. в первую очередь файлик package.json, во вторую - всё что в нём указано по тем путям которые там указаны.
    Вот когда ты делаешь npm link - открой node_modules и посмотри как должна выглядеть твоя либа(только без исходников).
    Когда ты сделаешь нормальный npm publish - токчно также всё просто скопируется в npm.
    Ответ написан
    Комментировать
  • Как работает функция обновления в React?

    Aetae
    @Aetae
    Тлен
    Вот так утрировано выглядит внутри функция useState:
    function useState(initialValue) {
      // подсчитываем вызовы useState в компоненте
      component.useStateCount++;
    
      // если уже был вызов этого useState(т.е. это не первая отрисовка)
      if (component.useStateCount in component.useStateCache) 
        // возвращаем результат из кэша
        return component.useStateCache[component.useStateCount];
    
      // если первый вызов - подготавливаем ответ вида [state, setState]
      const useStateResult = [
        initialValue, 
        function setState(callbackOrValue) {
          // если аргумент setState - функция
          if (typeof callbackOrValue === 'function') {
            // вызываем её с предыдущем значением в качестве аргумента и присваиваем результат вызова в state
            useStateResult[0] = callbackOrValue(useStateResult[0]);
          } else {
            // иначе просто присваиваем аргумент в state
            useStateResult[0] = callbackOrValue;
          }
    
          // вызов обновления компонента
          component.updateComounent(); 
        }
      ];
    
      // добавляем в кэш
      component.useStateCache[component.useStateCount] = useStateResult;
    
      // возвращаем
      return useStateResult;
    }

    Стало понятней?
    Ответ написан
    1 комментарий