Задать вопрос
Ответы пользователя по тегу React
  • Где выполнять запросы к серверу в MobX?

    Разделяй models и api
    Делай отдельно папку api и функции там с запросами к серверу, получениями ответа
    Делай отдельно папку
    -lib
      | -  helpers
      | -  utils


    И вот в helper или utils уже объединяй все это, пример:

    Функция из helpers/fetchUsers.ts
    const fetchUsers = async () => {
          setLoading(true) // mobx
          try {
              const response = await fetchUsers() // api
              setusers(response) // mobx
          } catch(e) {
              setError(e.message) // mobx
          } finally {
              setLoading(false) // mobx
          }
      }


    И потом вызываешь эту функцию

    это разделение делается для того, что бы не было никаких зависимостей
    API - это API
    MODELS - это MODELS

    Не нужно мешать это
    Ответ написан
    Комментировать
  • Почему navigate срабатывает в родительском компоненте, но не в дочернем?

    Рендеринг компонентов с верху вниз, с начало рендерится у тебя компонент App, а потом его дочерний элемент AuthManager, но так как ты вызываешь useRedirectToInitialPage в App, компонент AuthManager не успевает от рендерится, потому что в App useRedirectToInitialPage редеректит туда, куда ты указал
    Ответ написан
    Комментировать
  • Как исправить ошибку nextjs Warning: Expected server HTML to contain a matching in?

    @Brepex Автор вопроса
    Чтобы исправить эту ошибку, следует убедиться, что компоненты, которые используются в приложении, ведут себя одинаково как на сервере, так и на клиенте. А у меня мой
    Sidebar
    import { AnimatePresence, motion } from "framer-motion";
    import { useEffect, useState } from "react";
    import { MenuList } from "@features/sidebar";
    import { MakeOrderButton, PersonalAccount } from "@entities/sidebar";
    import { LogotypeIcon } from "@shared/images";
    import { useScreenResolution } from "@shared/libs/global";
    import { BurgerIcon, HorizontalLine } from "@shared/ui";
    import classes from "./Sidebar.module.scss";
    
    const initialSidebarAnimate = {
      x: -100,
      opacity: 0,
    };
    
    const animateSidebarAnimate = {
      x: 0,
      opacity: 1,
    };
    
    const exitSidebarAnimate = {
      x: -100,
      opacity: 0,
    };
    
    const transitionSidebarAnimate = {
      x: -100,
      opacity: 0,
    };
    
    export const Sidebar = () => {
      const [active, setActive] = useState<boolean>(false);
      const [isMobile, setIsMobile] = useState(false);
    
      const mobile = useScreenResolution();
      const handlerBurgerMenu = () => setActive((state) => !state);
    
      useEffect(() => {
        setIsMobile(mobile);
      }, [mobile]);
    
      return (
        <>
          <BurgerIcon onClick={handlerBurgerMenu} active={active} />
          <AnimatePresence>
            {(!isMobile || (isMobile && active)) && (
              <motion.header
                transition={transitionSidebarAnimate}
                initial={initialSidebarAnimate}
                animate={animateSidebarAnimate}
                exit={exitSidebarAnimate}
                className={classes.headerSidebar}
              >
                <LogotypeIcon className={classes.logotypeSidebar} />
                <MakeOrderButton className={classes.orderButton} />
                <HorizontalLine />
                <MenuList className={classes.menuList} />
                <HorizontalLine />
                <PersonalAccount className={classes.personalAccount} />
              </motion.header>
            )}
          </AnimatePresence>
        </>
      );
    };


    Отрисовывался по условию mobile, который присваивается на стороне клиента, поэтому надо это присваивание вынести в useEffect и ошибки не будет. Старый код Sidebar можно посмотреть в комментариях
    Ответ написан
  • Как типизировать функцию в vitest, что бы можно было вызвать у нее метод mockReturnValue?

    @Brepex Автор вопроса
    Нашел вот такой вариант реализации
    const mockUseScreenResolution = vi.mocked(useScreenResolution)
    mockUseScreenResolution. mockReturnValue("mobile")


    И там сразу типизация пробрасывается и создается нормально, юзайте
    Ответ написан
    Комментировать
  • Как замокать useState в vi тесте react?

    @Brepex Автор вопроса
    2. Типизация actual делается с помощью typeof React
    const actual:typeof React = await vi.importActual("react");
    Ответ написан
    Комментировать
  • Как реализовать drag and drop в редакторе текста с помощью draft-js?

    @Brepex Автор вопроса
    Для того что бы реализовать drag and drop, нужно реализовать вот ткую вот функцию
    const handlerDropAndDrop: DragEventHandler = async (
        event: DragEvent<HTMLDataElement>,
      ) => {
        event.preventDefault();
        const url = event.dataTransfer.getData("URL"); // Получаем src из фото, после чего закидываем его в функцию добавления картинки
        if (url) editorApi.addImage(url);
      };


    Но на данном этапе картинка будет просто дублироваться, что бы не было дублирования картинки, нужно добавить функцию удаления картинки, но перед этим обновим шаблон картинки
    import { ContentState } from "draft-js";
    import * as React from "react";
    import classes from "./Image.module.scss";
    
    type LinkProps = {
      contentState: ContentState;
      entityKey: string;
    };
    
    const Image: React.FC<LinkProps> = ({ contentState, entityKey }) => {
      /* Получаем url с помощью уникального ключа Entity */
      const { url } = contentState.getEntity(entityKey).getData();
    
      return (
        <img data-key={entityKey} className={classes.imageStyle} src={url} alt="" />
      );
    };
    export default Image;


    Добавим data-key={entityKey} через который мы будем получать entityKey и через него же будем удалять картинку. Добавим еще одну функцию обработчик
    const handlerDragAndDropExit: DragEventHandler = (
        event: DragEvent<HTMLDivElement>,
      ) => {
        event.preventDefault();
        const targetElement = event.target as HTMLElement; // Получаем тег img
        const entityKey = targetElement.getAttribute("data-key"); // Получаем у него наш entityKey
        if (entityKey) editorApi.removeImage(entityKey); передаем его в функцию удаления картинки
      };


    Функция удаления картинки которая находится в useEditor
    // Удаление картинки по его entityKey
      const removeImage = React.useCallback(
        (entityKey: string) => {
          setState((currentState) => {
            const contentState = currentState.getCurrentContent();
            const blockMap = contentState.getBlockMap();
    
            // Создаем новый массив блоков, исключая блок с указанным entityKey или блок без типа EntityType.image
            const newBlockMap: ContentBlock[] = [];
            blockMap.forEach((block) => {
              if (
                block &&
                (block.getEntityAt(0) !== entityKey || block.getType() !== "atomic")
              ) {
                newBlockMap.push(block);
              }
            });
    
            const newContentState = ContentState.createFromBlockArray(newBlockMap);
    
            return EditorState.push(currentState, newContentState, "remove-range");
          });
        },
        [setState],
      );


    Осталось только добавить все это в наши обработчики дива
    <div
          className={classes.textArea}
          onDrop={handlerDropAndDrop}
          onDragEnd={handlerDragAndDropExit}
        >
          <Editor
            ref={ref}
            placeholder={"Описание поста"}
            editorState={editorApi.state}
            onChange={editorApi.onChange}
          />
        </div>


    Готово, функция drag and drop реализована
    Ответ написан
    Комментировать
  • Почему не работает локальная библеотека на сборке Vite?

    @Brepex Автор вопроса
    Исправил на
    // index.d.ts
    
    declare module "custom-editor-lib" {
      import { ComponentType, Dispatch, SetStateAction } from "react";
      import { EditorState } from "draft-js";
    
      export interface EditorProps {
        value: EditorState;
        onChange: Dispatch<SetStateAction<EditorState>>;
      }
    
      export const Editor: ComponentType<EditorProps>;
    
      export function stateToHTML(editorState: EditorState): string;
    
      export function HTMLtoState(html: string): EditorState;
    }


    Проблема та же
    Ответ написан
  • Как сделать не точное сравнение в Routes React?

    @Brepex Автор вопроса
    решение проблемы было в том, что нужно использовать в родительском элементе, этот тег указывает react, где отображать вложенные элементы, импортируется он из
    import {Link, Outlet} from "react-router-dom";

    НО у меня почему то react не видит эту функцию, но она работает, так что если будите использовать, не обращайте внимания что реакт не видит его в инпорте, по крайней мере у меня так
    В кратце нужно этот Outlet прописать в header

    <Routes>
                    <Route path='/settings' element={<Header />}>
                        <Route index path='create' element={<CreateFieldProvider/>}/>
                        <Route path='lists' element={<FieldsList/>}/>
                    </Route>
                    <Route path={'/work'} element={<Work/>}/>
    
                </Routes>


    А вот сам header
    <>
            <header>
                <div className="content">
                    <div className={classes.header_wrapper}>
                        <div className={classes.wrapper_logo}>
                            <img src="/image/logo.png" alt=""/>
                        </div>
    
                        <div className={classes.wrapper_list}>
                            <Link to='/settings'>Главная</Link>
                            <Link to='/settings/create'>Создать </Link>
                            <Link to='/settings/lists'>Список </Link>
                        </div>
                    </div>
                </div>
            </header>
                {(loading_list || loading_create) && <Preloader />}
    
                <Outlet />
            </>
    Ответ написан
    Комментировать