Как установить мое состояние один раз при прослушивании события изменения размера

В моем реагирующем приложении мне нужно прослушивать событие изменения размера окна, поэтому, если размер окна меньше X, я вызову mobileFunc, если он больше X, я вызову desktopFunc для рендеринга некоторого html с большим количеством переменных. (Эти переменные и аргументы получают разные значения для desktopFunc и mobileFunc)

Я слушаю событие, однако каждое изменение размера окна снова и снова устанавливает мое состояние. Я не хочу этого делать. Я пытаюсь найти способ установить/изменить свое состояние, когда это необходимо, и, если возможно, уменьшить событие изменения размера прослушивания (необязательно). Я открыт для предложений по дебаунсингу, shouldComponentUpdate и т. д. Я должен найти эффективный способ.

// mobile is false by default in my state.
componentDidMount() {
    window.addEventListener('resize', this.setDeviceType)
}
componentWillUnmount(){
    window.removeEventListener('resize', this.setDeviceType)
}

setDeviceType() {
    if(window.innerWidth < 768) {
        this.setState({mobile: true})
    } else {
        this.setState({mobile: false})
    }
}

render() {
    return(
        <div>
            {this.state.mobile ? this.mobileFunc() : this.desktopFunc()}
        </div>
    )
}

person blocker    schedule 30.04.2019    source источник
comment
используйте debounce   -  person Zohir Salak    schedule 30.04.2019
comment
Как я могу это сделать? Можете ли вы привести пример на основе моего кода?   -  person blocker    schedule 30.04.2019
comment
Кстати, зачем это делать? Я редко вижу реальную потребность в том, чтобы что-то подобное действительно было в JS (хотя определенно есть варианты использования).   -  person Jared    schedule 01.05.2019


Ответы (2)


Я не проверял, но думаю, это может сработать...

// mobile is false by default in my state.
componentDidMount() {
    window.addEventListener('resize', this.setDeviceType)
}
componentWillUnmount(){
    window.removeEventListener('resize', this.setDeviceType)
}

setDeviceType() {
    const { mobile } = this.state;
    if(window.innerWidth < 768) {
        if(!mobile) {
            this.setState({mobile: true})
        }
    } else {
        if(mobile) {
            this.setState({mobile: false})
        }
    }
}

render() {
    const { mobile } = this.state;
    return(
        <div>
            {mobile ? this.mobileFunc() : this.desktopFunc()}
        </div>
    )
}

Этот блок if/else можно было бы немного почистить, но вы действительно онлайн, чтобы выполнить setState, если в настоящее время это не то, что вам нужно.

person Jared    schedule 30.04.2019
comment
это может иметь странные побочные эффекты setState является асинхронным, и событие изменения размера срабатывает очень быстро, это должно быть сделано с переменной экземпляра - person Zohir Salak; 30.04.2019
comment
Нет, я бы не стал использовать переменную экземпляра (для этого потребуется forceUpdate или некоторые дополнительные проверки). Во всяком случае, вы хотели бы отменить событие изменения размера, как вы упомянули в своем первоначальном комментарии. В качестве альтернативы вы можете использовать предыдущее состояние для дополнительных проверок (this.setState((prevState) => { ... });). Другой вариант, который я мог бы видеть, это удалить прослушиватель событий -> затем setState -> использовать обратный вызов setState, чтобы снова включить прослушиватель событий. Все это экспромтом, и, вероятно, у каждого варианта есть свои плюсы и минусы (или другие, о которых я не думаю). - person Jared; 01.05.2019

Вы можете использовать функцию debounce. Например, https://lodash.com/docs/#debounce

person Roman Unt    schedule 30.04.2019