Как разделить состояние, чтобы избежать повторного изменения в приложении react

#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 /…