#reactjs #react-hooks #react-state #react-state-management
#reactjs #реагирующие хуки #react-state #управление состоянием реакции
Вопрос:
Я создаю редактор на основе блоков с нуля. У меня есть модель как
initialState = {
id,
name,
blocks: [{
id,
content: [{text: '', attributes: []}]
}]
}
В моем редакторе React есть компонент, который будет иметь это состояние в useReducer.
const Editor: React.FC<Props> = ({ document }: Props) => {
const reducer = (state: any, action: any) =>
produce(state, (draft: any) => {
switch (action.operation) {
case ReducerActions.create: {
const index = draft.blocks.findIndex(
(block: any) => block.id === action.block.prevBlock,
);
draft.blocks.splice(index 1, 0, action.block);
break;
}
case ReducerActions.delete:
draft.blocks = draft.blocks.filter(
(block: any) => block.id !== action.blockId,
);
break;
case ReducerActions.updateContent: {
draft.blocks = draft.blocks.map((block: any) => {
if (block.id === action.blockId) {
return { ...block, content: action.content };
}
return block;
});
break;
}
}
});
const [state, dispatch]: any = useReducer(reducer, document, initialState);
const handleOnInput = (block: any, blockAction: any) => {
switch (blockAction.action) {
case BlockOperations.backSpace: {
const index = state.blocks.findIndex(
(elem: any) => elem.id === block.id,
);
if (index === 0 || index === -1) {
return;
}
const prevBlock = { ...state.blocks[index - 1] };
prevBlock.content = [...prevBlock.content, ...block.content];
dispatch({
operation: ReducerActions.updateContent,
blockId: prevBlock.id,
content: prevBlock.content,
});
dispatch({
operation: ReducerActions.delete,
blockId: block.id,
});
break;
}
}
};
return(
<div>
<Toolbar/>
<div id="editor">
{state.blocks.map((block: any) => (
<div key={block.id} id={block.id}>
<Block
key={block.id}
block={block}
onInput={handleOnInput}
onSelect={handleSelect}
/>
</div>
))}
</div>
</div>
)
}
Итак, я записал компонент блока и завернул все реквизиты для блока в useCallback, чтобы избежать повторной инициализации.
Но проблема началась с случая обратного ввода, когда мне нужно получить доступ к содержимому других блоков и создать новое содержимое. Итак, мне нужно последнее состояние, которое вынудило меня удалить useCallback и которое вносит все изменения в состояние повторного преобразования всего списка блоков.
Есть ли какой-либо способ, которым мы могли бы разделить состояние лучше и избежать повторного отображения всех блоков?
Один из подходов, который я имею в виду, заключается в том, чтобы позволить блокам управлять своим состоянием, и только при размытии редактируемого элемента будет обновляться состояние в родительском блоке. Но это повлияет на нас в будущем, когда нам может потребоваться совместная работа, или мы могли бы выполнять вызовы api непосредственно в содержимом блока для обновления конкретного блока. Поскольку внутренняя схема структурирована таким образом, что
documentModel = {
id,
name,
blockIds,
}
blockModel = {
id,
type,
content,
}
Спасибо за помощь.
Комментарии:
1. Что такого плохого в повторном рендеринге блоков?
2. @BennettDams как я уже сказал, это редактор на основе блоков. По сути, каждый абзац будет представлять собой блок, и каждый блок будет содержать редактируемый div, для которого каждый ход клавиши будет сохранен обратно в состояние, которое, в свою очередь, будет повторно отображать все блоки. Не будет ли это дорогостоящей операцией?
3. Повторное отображение не обязательно означает, что DOM обновляется, что является дорогостоящей частью. Я бы рекомендовал попробовать это, прежде чем прыгать через обручи, чтобы «оптимизировать производительность». Подробнее об этом от Кента К. Доддса: kentcdodds.com/blog /…