---
title: "Хук useBlocks — React API редактора Blok"
description: "Чтение и изменение блоков из React через useBlocks: вставка, перенос и перенос целого поддерева блоков."
source: https://blokeditor.com/ru/docs/use-blocks/
lastmod: 2026-09-07
---

Фреймворк JavaScript

Адаптеры фреймворков useBlocks

На этой странице getById(id)

# useBlocks(): работа с блоками из React

Реактивный снимок дерева блоков плюс полный API манипуляций от адаптеров фреймворков: хук useBlocks(editor, options?) в @bloklabs/react, composable useBlocks(editor, options?) в @bloklabs/vue и `injectBlocks(editor, options?)` в @bloklabs/angular — передайте сигнал `instance` у BlokEditorComponent/BlokContentDirective и вызывайте из контекста внедрения (инициализатора поля или конструктора). Чтения реактивно перерисовываются при изменении документа; записи атомарны (один шаг отмены) и безопасны до готовности редактора (превращаются в no-op). Возвращаемые объекты BlockNode ({ id, type, parentId, contentIds }) — волатильные свежие снимки: читайте их сразу, не сохраняйте в массивах зависимостей. По умолчанию реактивность охватывает весь документ: передайте `{ within: blockId }`, чтобы перерисовка происходила только при изменениях внутри поддерева этого блока (самого блока или любого его потомка). Используйте это в контейнерном блоке, который отрисовывает только собственных детей, — без ограничения области такой блок перерисовывается на каждое нажатие клавиши в любом месте документа, а страница из N контейнеров превращает одно нажатие в N перерисовок. Область ограничивает перерисовки, а не чтения: даже с заданной областью вы по-прежнему видите всё дерево, поэтому getById/getChildren продолжают работать с чем угодно. Во Vue область принимает ещё и ref/getter, а в Angular — signal, и значение читается в момент отправки изменения, поэтому его смена не требует переподписки.

Обновлено 7 авг. 2026 г. [Редактировать на GitHub](https://github.com/JackUait/blok/blob/main/docs/src/components/api/api-data.ts)

## Методы

### getById(id)

BlockNode | null

Блок с данным id как снимок-узел, или null для неизвестного id.

TypeScript

```
const node = blocks.getById('x9k2f1');
// → { id: 'x9k2f1', type: 'paragraph', parentId: null, contentIds: [] }
```

### getChildren(parentId)

BlockNode[]

Прямые дети родительского блока в порядке документа. Передайте null для корневых блоков.

TypeScript

```
const rootBlocks = blocks.getChildren(null);
const rowBlocks = blocks.getChildren(databaseBlockId);
```

### insert(spec?)

BlockNode | null

Вставить один блок (type, data, parentId, position, tunes, id, focus/caret, replace). `replace: true` вместе с `position`, указывающим на существующий блок, заменяет этот блок, а не вставляет рядом — программный «turn into». Возвращает созданный узел или null при отклонении (неизвестный тип инструмента, несуществующий parentId или `replace`, чья цель отсутствует). Явный уже существующий id — insert-if-absent. Атомарно — один шаг отмены.

TypeScript

```
const node = blocks.insert({
  type: 'header',
  data: { text: 'New section', level: 2 },
  position: 'end',
  focus: true,
});
// → node.id is the new block's id (or null if rejected)
```

### insertMany(specs)

BlockNode[]

Вставить несколько блоков атомарно, в порядке массива, ОДНИМ шагом отмены. Неудачные спецификации отбрасываются; возвращаются успешно созданные узлы.

TypeScript

```
const nodes = blocks.insertMany([
  { type: 'header', data: { text: 'Title' } },
  { type: 'paragraph', data: { text: 'Body' } },
]);
```

### insertTree(spec)

BlockNode | null

Вставить готовое ВЛОЖЕННОЕ поддерево одной атомарной операцией. Дети вставляются под свой узел рекурсивно; параметры размещения применяются только к корню. Возвращает корневой узел или null при отклонённом/конфликтующем id.

TypeScript

```
const root = blocks.insertTree({
  type: 'toggle',
  data: { text: 'Details' },
  children: [
    { type: 'paragraph', data: { text: 'Hidden content' } },
  ],
});
```

### insertMarkdown(markdown, options?)

Promise<BlockNode[]>

Преобразовать Markdown-строку в блоки и вставить их АДДИТИВНО (без очистки документа). Асинхронно — конвертер загружается лениво. Возвращает все созданные узлы в порядке документа; пустой ввод или несуществующий parentId возвращает [].

TypeScript

```
const nodes = await blocks.insertMarkdown(
  '# Title\n\n- one\n- two',
  { position: 'end' },
);
```

### exportMarkdown()

Promise<string>

Сериализовать ВЕСЬ документ в Markdown (асинхронно, ленивый сериализатор). Структура, невыразимая в Markdown (например, объединённые ячейки таблиц), отбрасывается.

TypeScript

```
const md = await blocks.exportMarkdown();
```

### markdownToBlocks(md, config?)

Promise<OutputBlockData[]>

Преобразовать Markdown в блоки БЕЗ экземпляра редактора — это отдельный подпуть `@bloklabs/core/markdown`, а не метод хука. Ему не нужны ни DOM, ни смонтированный Blok, поэтому он закрывает серверный сценарий, недоступный insertMarkdown/exportMarkdown: импорт Markdown в Node-задаче, наполнение документа или предвычисление `data` до монтирования редактора. `config` — это `MarkdownImportConfig` (сопоставление инструментов, GFM, расширения). Результат готов для `blocks.render()` или `blocks.insertMany()`.

TypeScript

```
import { markdownToBlocks } from '@bloklabs/core/markdown';

// No editor instance required — this also runs on the server
const parsed = await markdownToBlocks('# Title\n\n- one\n- two');

// -> OutputBlockData[]; store it, or hand it to a live editor
await blocks.render({ blocks: parsed });
```

### markdownToBlocksWithReport(md, config?)

Promise<{ blocks: OutputBlockData[]; warnings: MarkdownDegradation[] }>

Те же блоки плюс то, что Markdown не смог в них перенести. В Blok нет блока для сырого HTML, поэтому разметка, записанная в Markdown, экранируется и сохраняется как литеральный текст — безопасно, но молча. Берите этот метод, когда импорт идёт без присмотра (инструмент MCP, агент, массовая миграция) и кому-то нужно сообщить, что изменилось. Его исходящий близнец — blocksToMarkdownWithReport в @bloklabs/core/view.

TypeScript

```
import { markdownToBlocksWithReport } from '@bloklabs/core/markdown';

const { blocks: parsed, warnings } = await markdownToBlocksWithReport(source);
// warnings: [{ construct: 'html', action: 'degraded', detail: 'HTML is escaped and stored as literal text…' }]

if (warnings.length === 0) {
  await blocks.render({ blocks: parsed });
}
```

### move(id, target)

void

Переместить блок в плоский слот: { before }, { after } или { toIndex }. Блок принимает родителя места назначения — используйте nest/unnest, чтобы сменить родителя без выбора соседнего слота.

TypeScript

```
blocks.move(nodeId, { after: otherId });
blocks.move(nodeId, { toIndex: 0 });
```

### nest(id, parentId)

void

Сделать блок ребёнком другого блока.

TypeScript

```
blocks.nest(childId, toggleId);
```

### unnest(id)

void

Поднять вложенный блок на уровень выше (из его родителя).

TypeScript

```
blocks.unnest(childId);
```

### remove(id)

void

Удалить блок (и его поддерево).

TypeScript

```
blocks.remove(nodeId);
```

### update(id, data?, tunes?)

void

Обновить данные и/или тюны блока по id. Делегирует асинхронному blocks.update ядра (собственный шаг отмены); неизвестные id — тихий no-op.

TypeScript

```
blocks.update(nodeId, { text: 'Edited' });
```

### convert(id, newType, dataOverrides?, options?)

void

Преобразовать блок в другой тип («turn into»). Оба инструмента должны определять conversionConfig; непреобразуемый блок — корректный no-op. options.caret ставит курсор в преобразованный блок.

TypeScript

```
blocks.convert(nodeId, 'header', { level: 2 });
```

### transact(fn)

void

Выполнить несколько мутаций как ОДИН атомарный шаг отмены.

TypeScript

```
blocks.transact(() => {
  blocks.remove(oldId);
  blocks.insert({ type: 'paragraph', data: { text: 'Replacement' } });
});
```

### transactWithoutCapture(fn)

void

Как transact, но операция НЕ попадает в историю отмены — для тихой авто-починки/нормализации, через которую CMD+Z не должен проходить.

TypeScript

```
blocks.transactWithoutCapture(() => {
  blocks.update(nodeId, { text: normalized });
});
```

### splitBlock(currentBlockId, currentBlockData, newBlockType, newBlockData, insertIndex)

BlockNode | null

Атомарно разделить блок: обновить текущий блок и вставить новый по абсолютному плоскому индексу — ОДНИМ шагом отмены.

TypeScript

```
const newNode = blocks.splitBlock(
  nodeId, { text: 'First half' },
  'paragraph', { text: 'Second half' },
  blocks.getBlockIndex(nodeId)! + 1,
);
```

### insertInsideParent(parentId, insertIndex, childData?)

BlockNode | null

Вставить одного ребёнка под родителя по плоскому индексу атомарно (создание И назначение родителя ОДНИМ шагом отмены) — предпочтительнее insert() + nest(), которые дают два шага.

TypeScript

```
const child = blocks.insertInsideParent(toggleId, 3);
```

### insertOutputData(blocks, options?)

BlockNode[]

Вставить плоский массив уже сериализованных OutputBlockData (форма save()) напрямую, с учётом связей parent/content. Один атомарный шаг отмены.

TypeScript

```
const nodes = blocks.insertOutputData(savedFragment.blocks);
```

### render(data)

Promise<void>

Заменить ВЕСЬ документ блоками из сохранённых OutputData — примитив ЗАГРУЗКИ документа, который сначала очищает содержимое (в отличие от аддитивных вставок).

TypeScript

```
await blocks.render(savedData);
```

### renderFromHTML(html)

Promise<void>

Заменить ВЕСЬ документ блоками, разобранными из HTML-строки (сначала очищает содержимое).

TypeScript

```
await blocks.renderFromHTML('<h1>Imported</h1><p>Body</p>');
```

### clear()

Promise<void>

Удалить все блоки из документа.

TypeScript

```
await blocks.clear();
```

### getBlocksCount()

number

Текущее количество блоков (реактивно).

TypeScript

```
const count = blocks.getBlocksCount();
```

### getCurrentBlockIndex()

number

Плоский индекс блока с курсором, или -1, если курсора нет.

TypeScript

```
const index = blocks.getCurrentBlockIndex();
```

### getBlockByIndex(index)

BlockNode | null

Блок по плоскому индексу как снимок-узел, или null.

TypeScript

```
const first = blocks.getBlockByIndex(0);
```

### getBlockIndex(id)

number | null

Абсолютный плоский индекс блока по id, или null для неизвестного.

TypeScript

```
const index = blocks.getBlockIndex(nodeId);
```

### getBlockData(id)

{ data, tunes } | null

Прочитать текущие данные и тюны блока по id без каких-либо мутаций — дубликат блока собирается прямо из хука: прочитать узел, затем insert({ type, data, tunes }).

TypeScript

```
const saved = blocks.getBlockData(nodeId);
if (saved) {
  blocks.insert({ type: 'paragraph', data: saved.data, position: { after: nodeId } });
}
```

### getBlockByElement(element)

BlockNode | null

Блок, чей holder содержит/равен DOM-элементу — сопоставляет цель события обратно с блоком.

TypeScript

```
const node = blocks.getBlockByElement(event.target as HTMLElement);
```

### composeBlockData(toolName)

Promise<BlockToolData>

Прочитать пустые данные инструмента по умолчанию без вставки. Отклоняется для неизвестного инструмента.

TypeScript

```
const defaults = await blocks.composeBlockData('header');
```

### isSyncingFromYjs()

boolean

Идёт ли сейчас синхронизация Yjs (undo/redo) — используйте, чтобы пропустить очистку, которая конфликтовала бы с состоянием отмены.

TypeScript

```
if (!blocks.isSyncingFromYjs()) {
  blocks.update(nodeId, { text: cleaned });
}
```

TypeScript

```
import { useBlok, BlokContent, useBlocks } from '@bloklabs/react';

export function Outline() {
  const editor = useBlok({ tools });
  const blocks = useBlocks(editor);

  // Reactive: re-renders whenever the document changes.
  const rootBlocks = blocks.getChildren(null);

  return (
    <>
      <BlokContent editor={editor} />
      <ol>{rootBlocks.map((b) => <li key={b.id}>{b.type}</li>)}</ol>
    </>
  );
}

// Inside a container block: re-render only for its OWN subtree, so typing in an
// unrelated block elsewhere in the document costs this component nothing.
function Steps({ block }) {
  const blocks = useBlocks(useBlokInstance(), { within: block.id });
  const steps = blocks.getChildren(block.id);

  return <ol>{steps.map((s) => <li key={s.id}>{s.type}</li>)}</ol>;
}
```
