Некоторое время назад я был вынужден ковыряться в 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
можно тут
Спасибо за внимание!
Искренне надеюсь, что рассмотренные хуки помогут вам добавлять фичи в легаси ничего не сломав)