Контекст
Контекст — способ передать данные всем вложенным компонентам сразу, не прокидывая их пропсами через каждый уровень. Обычно через контекст раздают то, что нужно во многих местах: список задач с функциями изменения, текущего пользователя, тему оформления.
Создание контекста
Создайте файл src/context/TodoContext.jsx. В нём будут сам контекст, компонент-поставщик и функция для чтения:
// src/context/TodoContext.jsx
import { createContext, useContext } from 'solid-js';
import { createStore } from 'solid-js/store';
const TodoContext = createContext();
export function TodoProvider(props) {
const [todos, setTodos] = createStore([]);
const add = (title) => setTodos(todos.length, { id: Date.now(), title, done: false });
const toggle = (id) => setTodos((t) => t.id === id, 'done', (d) => !d);
return (
<TodoContext.Provider value={{ todos, add, toggle }}>
{props.children}
</TodoContext.Provider>
);
}
export function useTodos() {
return useContext(TodoContext);
}TodoProvider создаёт хранилище и кладёт его вместе с функциями в атрибут value. Всё, что окажется внутри поставщика, сможет получить это значение.
Подключение поставщика
Оберните приложение в TodoProvider:
// src/App.jsx
import { TodoProvider } from './context/TodoContext';
import AddTodo from './components/AddTodo';
import TodoList from './components/TodoList';
export default function App() {
return (
<TodoProvider>
<h1>Мои задачи</h1>
<AddTodo />
<TodoList />
</TodoProvider>
);
}Чтение контекста
Компоненты внутри получают данные вызовом useTodos():
// src/components/TodoList.jsx
import { For } from 'solid-js';
import { useTodos } from '../context/TodoContext';
export default function TodoList() {
const { todos, toggle } = useTodos();
return (
<ul>
<For each={todos}>
{(todo) => <li onClick={() => toggle(todo.id)}>{todo.title}</li>}
</For>
</ul>
);
}// src/components/AddTodo.jsx
import { useTodos } from '../context/TodoContext';
export default function AddTodo() {
const { add } = useTodos();
return <button onClick={() => add('Новая задача')}>Добавить</button>;
}Нажатие на кнопку в AddTodo добавляет задачу, и она сразу появляется в TodoList, хотя эти компоненты не связаны пропсами. Деструктурировать значение контекста здесь можно: todos — хранилище, оно остаётся реактивным.
Что где лежит
| Часть | Назначение |
|---|---|
createContext() | Создаёт контекст |
Context.Provider | Задаёт значение для вложенных компонентов |
useContext(Context) | Читает значение |
Частая ошибка
Вызывать useTodos() в компоненте, который находится вне TodoProvider, например прямо в App. Функция вернёт undefined, и обращение к todos выдаст ошибку. Поставщик должен быть выше по дереву, чем все компоненты, которые читают контекст.