Интеграция с Redux

Slim.js — это лёгкая библиотека для создания реактивных компонентов в JavaScript, предоставляющая минималистичный, но мощный API для управления состоянием и обновления DOM. В сочетании с Redux она позволяет централизованно управлять глобальным состоянием приложения, сохраняя преимущества реактивного рендеринга.

Redux реализует концепцию единого хранилища (store) и предсказуемых изменений состояния через actions и reducers. В Slim.js интеграция с Redux строится вокруг подписки компонентов на изменения состояния и диспатча действий.


Подключение Redux к компоненту Slim.js

Для начала требуется импортировать необходимые элементы Redux:

import { createStore } from 'redux';
import Slim from 'slim-js';

Создаём базовый редуктор и хранилище:

const initialState = {
    counter: 0
};

function counterReducer(state = initialState, action) {
    switch (action.type) {
        case 'INCREMENT':
            return { ...state, counter: state.counter + 1 };
        case 'DECREMENT':
            return { ...state, counter: state.counter - 1 };
        default:
            return state;
    }
}

const store = createStore(counterReducer);

Slim.js-компонент может подписываться на изменения состояния следующим образом:

class CounterComponent extends Slim {
    get useShadow() {
        return false;
    }

    onBeforeCreated() {
        this.state = store.getState();
        store.subscribe(() => {
            this.state = store.getState();
            this.render();
        });
    }

    increment() {
        store.dispatch({ type: 'INCREMENT' });
    }

    decrement() {
        store.dispatch({ type: 'DECREMENT' });
    }

    render() {
        return `
            <div>
                <h2>Счётчик: ${this.state.counter}</h2>
                <button oncl ick="this.increment()">+</button>
                <button oncl ick="this.decrement()">-</button>
            </div>
        `;
    }
}

Slim.define('counter-component', CounterComponent);

Ключевые моменты:

  • onBeforeCreated используется для инициализации локального состояния из Redux и подписки на изменения.
  • Вызов store.subscribe() гарантирует, что компонент будет реагировать на любые изменения в хранилище.
  • Методы компонента диспатчат действия напрямую в Redux, обеспечивая синхронизацию глобального состояния.

Создание реактивных свойств из состояния Redux

Slim.js поддерживает реактивные свойства через геттеры/сеттеры. Для интеграции с Redux можно создать вспомогательный метод, который автоматически обновляет компонент при изменении состояния.

class ReactiveComponent extends Slim {
    get useShadow() {
        return false;
    }

    onBeforeCreated() {
        this.reduxState = store.getState();
        store.subscribe(() => this.updateState(store.getState()));
    }

    updateState(newState) {
        this.reduxState = newState;
        this.render();
    }
}

Этот подход позволяет компоненту не обращаться к глобальному store в каждом методе, а работать с реактивной локальной копией состояния.


Обработка сложных состояний

Для сложных приложений с несколькими модулями состояния полезно разделять редукторы:

import { combineReducers, createStore } from 'redux';

const userReducer = (state = { name: '' }, action) => {
    switch (action.type) {
        case 'SET_NAME':
            return { ...state, name: action.payload };
        default:
            return state;
    }
};

const settingsReducer = (state = { theme: 'light' }, action) => {
    switch (action.type) {
        case 'SET_THEME':
            return { ...state, theme: action.payload };
        default:
            return state;
    }
};

const rootReducer = combineReducers({
    user: userReducer,
    settings: settingsReducer
});

const store = createStore(rootReducer);

Компоненты Slim.js могут подписываться на отдельные ветки состояния, минимизируя лишние перерисовки:

class UserComponent extends Slim {
    get useShadow() { return false; }

    onBeforeCreated() {
        this.user = store.getState().user;
        store.subscribe(() => {
            const newUser = store.getState().user;
            if (newUser !== this.user) {
                this.user = newUser;
                this.render();
            }
        });
    }

    setName(name) {
        store.dispatch({ type: 'SET_NAME', payload: name });
    }

    render() {
        return `
            <div>
                <p>Имя: ${this.user.name}</p>
                <input type="text" onin put="this.setName(this.value)" placeholder="Введите имя"/>
            </div>
        `;
    }
}

Slim.define('user-component', UserComponent);

Особенности:

  • Выборочная подписка на ветку состояния повышает производительность.
  • Использование локальной копии состояния снижает количество ненужных рендеров.

Middleware и асинхронные действия

Redux поддерживает middleware, например redux-thunk, для обработки асинхронных действий:

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';

const fetchUser = () => async (dispatch) => {
    const response = await fetch('/api/user');
    const data = await response.json();
    dispatch({ type: 'SET_USER', payload: data });
};

const store = createStore(rootReducer, applyMiddleware(thunk));

Slim.js-компоненты могут вызывать такие асинхронные действия:

class AsyncUserComponent extends Slim {
    get useShadow() { return false; }

    onBeforeCreated() {
        this.user = store.getState().user;
        store.subscribe(() => {
            this.user = store.getState().user;
            this.render();
        });
    }

    loadUser() {
        store.dispatch(fetchUser());
    }

    render() {
        return `
            <div>
                <p>Имя: ${this.user.name || 'Загрузка...'}</p>
                <button oncl ick="this.loadUser()">Загрузить данные</button>
            </div>
        `;
    }
}

Slim.define('async-user-component', AsyncUserComponent);

Асинхронные действия позволяют отделять логику получения данных от компонентов и поддерживают чистоту архитектуры.


Рекомендации по интеграции

  • Использовать локальные реактивные свойства для минимизации лишних перерисовок.
  • Подписываться на конкретные ветки состояния, если Redux-хранилище большое.
  • Разделять бизнес-логику в actions и reducers, оставляя компоненты Slim.js максимально простыми.
  • Для асинхронных операций применять middleware (redux-thunk или redux-saga).
  • Избегать прямого изменения состояния Redux внутри компонента — всегда использовать dispatch.

С помощью этих подходов Slim.js становится эффективным инструментом для построения реактивного интерфейса с централизованным управлением состоянием через Redux, сочетая простоту компонентов с предсказуемостью и масштабируемостью архитектуры.