#javascript #reactjs #react-hooks #dom-events
#javascript #reactjs #реагирующие перехваты #dom-события
Вопрос:
У меня есть хук, который прослушивает window.resize
событие. Я хочу только прослушивать и обновлять при window.innerWidth
изменениях. Я хочу игнорировать изменения window.innerHeight
, поскольку это срабатывает при открытии программной клавиатуры. Проблема в том, что размер среды хранится в моем хранилище Redux, что приводит к повторному отображению приложения при открытии программной клавиатуры.
Мой код срабатывает на обоих window.innerWidth
и window.innerHeight
изменяется, как я могу изменить это поведение?
Мой хук
import { useState, useEffect } from 'react';
// Hook
export const useWindowSize = () => {
const isClient = typeof window === 'object'; //Object represents browser window
function getSize() {
return {
width: isClient ? window.innerWidth : undefined
}
}
const [windowSize, setWindowSize] = useState(getSize)
useEffect(() => {
if (!isClient) { return false } //Exit if not user/browser
function handleResize() {
setWindowSize(getSize())
}
window.addEventListener('resize', handleResize) // <-- I am only interested in window.innerWidth !
return () => window.removeEventListener('resize', handleResize)
}, []) // Empty array ensures that effect is only run on mount and unmount
return windowSize
}
Реализация в моем AppRouter.js
const AppRouter = ({ isNavOpen, mediaSize, startSetMediaSize, language, ...rest }) => {
//** Start mediaQuery */
const mediaBreakpoints = {
smallStr: styles['breakpoint-small-value'],
mediumStr: styles['breakpoint-medium-value'],
largeStr: styles['breakpoint-large-value'],
smallInt: new Number(styles['breakpoint-small-value']).valueOf(),
mediumInt: new Number(styles['breakpoint-medium-value']).valueOf(),
largeInt: new Number(styles['breakpoint-large-value']).valueOf(),
small: styles['breakpoint-small'],
medium: styles['breakpoint-medium'],
large: styles['breakpoint-large']
}
//Calculate media size
const screenWidth = useWindowSize().width
...
useEffect(() => {
if (screenWidth > mediaBreakpoints.largeInt) {
if (mediaSize !== MEDIA_LARGE) { startSetMediaSize(MEDIA_LARGE) }
} else if (screenWidth > mediaBreakpoints.mediumInt) {
if (mediaSize !== MEDIA_MEDIUM) { startSetMediaSize(MEDIA_MEDIUM) }
} else if (screenWidth > mediaBreakpoints.smallInt) {
if (mediaSize !== MEDIA_SMALL) { startSetMediaSize(MEDIA_SMALL) }
} else {
//Tiny and small are treated equally
if (mediaSize !== MEDIA_SMALL) { startSetMediaSize(MEDIA_SMALL) }
}
}, [screenWidth]) // Only run if screen width changes
}
const mapStateToProps = (state) => ({
isNavOpen : state.ui.isOpen,
mediaSize: state.ui.mediaSize, //small / medium / large
language: state.usersettings.language //se||en
})
const mapDispatchToProps = (dispatch) => ({
startSetNavigationState: (isOpen) => dispatch(setNavigationState(isOpen)),
startSetMediaSize: (mediaSize) => dispatch(setMediaSize(mediaSize))
})
//export default AppRouter
export default connect(mapStateToProps, mapDispatchToProps)(AppRouter)
Моя точка монтирования для AppRouter
const jsx = (
<React.StrictMode>
<Provider store={store}>
<AppRouter />
</Provider>
</React.StrictMode>
)
С уважением / K
Ответ №1:
Простое решение, которое я могу придумать, — это кэшировать последнюю внутреннюю ширину и выполнять логику изменения размера только в том случае, если она изменилась. Что-то вроде этого:
import { useState, useEffect, useRef } from 'react';
// Hook
export const useWindowSize = () => {
const isClient = typeof window === 'object'; //Object represents browser window
const lastWidth = useRef();
function getSize() {
return {
width: isClient ? window.innerWidth : undefined
}
}
const [windowSize, setWindowSize] = useState(getSize)
useEffect(() => {
if (!isClient) { return false } //Exit if not user/browser
function handleResize() {
if (window?.innerWidth !== lastWidth.current) {
const width = getSize();
lastWidth.current = width;
setWindowSize(width)
}
}
window.addEventListener('resize', handleResize) // <-- I am only interested in window.innerWidth !
return () => window.removeEventListener('resize', handleResize)
}, []) // Empty array ensures that effect is only run on mount and unmount
return windowSize
}
Комментарии:
1. Большое спасибо @Sagi! Это сработало как шарм! (^ __ ^)/ Я раньше не использовал хук useRef, прочитаю об этом! С уважением / K