Некоторое время назад я был вынужден ковыряться в legacy, оставленным ушедшим разработчиком. Добавление фичи в код было хирургической операцией, которая легко могла сломать жизнеспособность страницы. Из-за нагроможденных useEffect с связями между собой, скорее всего, под конец, как работает код не понимал и сам автор. На проекте не было линтера

Мне очень помогли следующие хуки и сделанные по аналогии

1. useListEditor()

Хук, который можно использовать для обработки редактирования списка элементов. Позволяет сразу получить уже собранный массив в коллбеке onChange, что упрощает применение изменений из списка

import { useListEditor } from "react-declarative";

export const EditableList = () => {
  const { 
    onRemoveItem,
    onUpdateItem,
    onAddItem,
    render,
  } = useListEditor(
    (id, item) => (
      <>
        <span>{`Label: ${item.label}`}</span>
        <span>{`Value: ${item.value}`}</span>
        <button
          onClick={() =>
            onUpdateItem(id, {
              label: prompt("label", item.label),
              value: prompt("value", item.value)
            })
          }
        >
          update
        </button>
        <button onClick={() => onRemoveItem(id)}>remove</button>
      </>
    ),
    {
      initialValue: [
        {
          label: "foo",
          value: "bar"
        }
      ],
      onChange: (items) => console.log(items)
    }
  );

  return (
    <>
      <button
        style={{
          marginBottom: 5
        }}
        onClick={() =>
          onAddItem({
            label: "fiz",
            value: "baz"
          })
        }
      >
        Add item
      </button>
      <div
        style={{
          display: "grid",
          gridTemplateColumns: "1fr 1fr auto auto",
          gridColumnGap: 5,
          gridRowGap: 5,
          maxWidth: 300
        }}
      >
        {render()}
      </div>
    </>
  );
};

export default EditableList;

Посмотреть код хука useListEditor можно тут

2. useModalDialog()

Хук, который позволяет вывести модальное окно с привязкой к состоянию компонента. Дочернее древо элементов рисуется в <ModelProvider>, который можно разместить в App или другом нижестоящем компоненте

import { useState } from "react";

import { useModal } from "react-declarative";

export const ModalDialogExample = () => {
  const [value, setValue] = useState(1);

  const { showModal, hideModal } = useModal(
    () => (
      <div>
        Sample modal with value {value}
      </div>
    ),
    [value]
  );

  return (
    <>
      <button onClick={showModal}>Show modal</button>
      <button onClick={hideModal}>Hide modal</button>
      <button onClick={() => setValue(value + 1)}>Increment</button>
    </>
  );
};

export default ModalDialogExample;

Посмотреть код хука useModalDialog можно тут

3. useActualCallback()

Позволяет достучаться до актуальной ссылки на коллбек из useEffect даже если функция не указана в зависимостях или не все состояния, используемые в функции, есть в зависимостях эффекта

Казалось бы, при открытии формы должен появиться alert() с содержимым {never: null}, однако, внутри коллбека значение initNotComplete всегда будет актуальным

import { useState, useEffect, useLayoutEffect } from "react";

import { useActualCallback } from "react-declarative";

export const ActualCallbackExample = () => {
  const [initNotComplete, setInitNotComplete] = useState(true);

  const [filterData, setFilterData] = useState({
    never: null
  });

  const handleChange = useActualCallback(() => {
    if (!initNotComplete) {
      alert(JSON.stringify(filterData, null, 2));
    }
  });

  useEffect(() => {
    handleChange();
  }, [filterData]);

  useLayoutEffect(() => {
    setInitNotComplete(false);
  }, []);

  return (
    <button
      onClick={() =>
        setFilterData({
          foo: "bar"
        })
      }
    >
      Update filterData
    </button>
  );
};

export default ActualCallbackExample;

Посмотреть код хука useActualCallback можно тут

Спасибо за внимание!

Искренне надеюсь, что рассмотренные хуки помогут вам добавлять фичи в легаси ничего не сломав)

Комментарии (0)