Подтвердить что ты не робот

Window Resize - React + Redux

Я новичок в Redux, и мне интересно, есть ли у кого-нибудь советы по передовым методам обработки нереактивных событий, таких как изменение размера окна. В своем исследовании я нашел эту ссылку из официальной документации React: https://facebook.github.io/react/tips/dom-event-listeners.html

Мои вопросы: при использовании Redux я должен хранить размер окна в своем Магазине или я должен хранить его в моем состоянии отдельных компонентов?

4b9b3361

Ответ 1

Хороший вопрос. Мне нравится иметь часть моего магазина. Редуктор, для которого может выглядеть так:
const initialState = {
    screenWidth: typeof window === 'object' ? window.innerWidth : null
};

function uiReducer(state = initialState, action) {
    switch (action.type) {
        case SCREEN_RESIZE:
            return Object.assign({}, state, {
                screenWidth: action.screenWidth
            });
    }
    return state;
}

Действие, для которого довольно шаблонный. (SCREEN_RESIZE является постоянной строкой.)

function screenResize(width) {
    return {
        type: SCREEN_RESIZE,
        screenWidth: width
    };
}

Наконец, вы подключаете его вместе с прослушивателем событий. Я бы поставил следующий код в том месте, где вы инициализируете свою переменную store.

window.addEventListener('resize', () => {
    store.dispatch(screenResize(window.innerWidth));
});

Запросы мультимедиа

Если ваше приложение принимает более двоичный вид размера экрана (например, большой/маленький), вы можете вместо этого использовать медиа-запрос. например.

const mediaQuery = window.matchMedia('(min-width: 650px)');

if (mediaQuery.matches) {
    store.dispatch(setLargeScreen());
} else {
    store.dispatch(setSmallScreen());
}

mediaQuery.addListener((mq) => {
    if (mq.matches) {
        store.dispatch(setLargeScreen());
    } else {
        store.dispatch(setSmallScreen());
    }
});

(на этот раз я оставлю код действия и редуктора. Это довольно очевидно, как они выглядят.)

Один из недостатков этого подхода заключается в том, что хранилище может быть инициализировано с неправильным значением, и мы полагаемся на запрос СМИ, чтобы установить правильное значение после того, как хранилище было инициализировано. Я не знаю, как это сделать. Обратная связь приветствуется.

UPDATE

Теперь, когда я думаю об этом, вы можете обойти это, сделав что-то вроде следующего. (Но будьте осторожны, я не проверял это.)

const mediaQuery = window.matchMedia('(min-width: 650px)');

const store = createStore(reducer, {
    ui: {
        largeScreen: mediaQuery.matches
    }
});

mediaQuery.addListener((mq) => {
    if (mq.matches) {
        store.dispatch(setLargeScreen());
    } else {
        store.dispatch(setSmallScreen());
    }
});

ОБНОВЛЕНИЕ II: Недостаток этого последнего подхода заключается в том, что объект ui заменит целое состояние ui не только поле largeScreen. Независимо от того, что происходит из исходного состояния ui, теряется.

Ответ 2

Используйте redux-responsive для обработки реагирующего состояния вашего приложения. Он использует усилитель хранилища для управления выделенной областью (свойством) вашего состояния хранилища (обычно называемой "браузер" ) через свой собственный редуктор, так что вам не нужно явно добавлять слушателей событий в объект документа.

Все, что вам нужно сделать, это сопоставить браузеру. width, browser.height и т.д. с компонентами вашего компонента. Обратите внимание, что для обновления этих значений отвечает только редуктор, определенный в redux-responsive.

Ответ 3

У меня есть аналогичный случай, когда мне нужен размер окна для целей, отличных от реагирования. Согласно this, вы также можете использовать redux-thunk:

function listenToWindowEvent(name, mapEventToAction, filter = (e) => true) {
  return function (dispatch) {
    function handleEvent(e) {
      if (filter(e)) {
        dispatch(mapEventToAction(e));
      }
    }

    window.addEventListener(name, handleEvent);

    // note: returns a function to unsubscribe
    return () => window.removeEventListener(name, handleEvent);
  };
}

// turns DOM event into action,
// you can define many of those
function globalKeyPress(e) {
  return {
    type: 'GLOBAL_KEY_PRESS',
    key: e.key
  };
}

// subscribe to event
let unlistenKeyPress = store.dispatch(listenToWindowEvent('keypress', globalKeyPress));
// eventually unsubscribe
unlistenKeyPress();

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