PureComponent продолжает рендеринг, даже если состояние / реквизит не изменяется

#reactjs #react-redux #react-component

#reactjs #react-redux #реагирующий компонент

Вопрос:

Я пытаюсь изучить и протестировать React.PureComponent и он продолжает рендеринг, даже если состояние этого чистого компонента не изменяется.

Мой PureComponent очень прост и принимает только одну функцию Redux Action через connect hoc

 import React from 'react';
import {
    Container,
    Button
} from 'reactstrap'
import { connect } from 'react-redux'
import { resetWorkouts } from '../actions/workoutApiActions'

class About extends React.PureComponent {
    render () {
        const { resetWorkouts } = this.props;
        console.log('in about render...')
        return (
            <React.Fragment>
                <Container>
                    <h2>Api Data Reset</h2>
                    <Button color="danger" onClick={resetWorkouts}>Reset Data</Button>
                </Container>
            </React.Fragment>
        );
    }
}

const mapDispatchToProps = dispatch => {
    return {
        resetWorkouts: () => dispatch(resetWorkouts())
    }
}

export default connect(null, mapDispatchToProps)(About);
  

В приведенном выше коде вы можете видеть, что в компоненте нет состояния. Он принимает функцию действия только как props from connect . Однако всякий раз, когда я нажимаю на Reset Data кнопку, он продолжает вызывать render метод, как показано на скриншоте.

введите описание изображения здесь

На скриншоте я вижу, что глобальное хранилище состояний изменяется всякий раз, когда я нажимаю кнопку. Но это состояние не используется в моем PureComponent, и оно должно быть вне области видимости, и мой компонент должен игнорировать повторный рендеринг.

Или функции действия Redux создаются каждый раз, когда изменяется глобальное хранилище состояний. И передается как новый объект моему PureComponent ?

Теоретически мне не нужно писать свою собственную shouldComponentUpdate функцию, верно? Я в замешательстве, и не могли бы вы, пожалуйста, помочь мне разобраться в этом поведении?

Моя цель — я не хочу, чтобы мой PureComponent снова отображался, когда пользователь нажимает кнопку.

Обновления:

Я пробовал следующее в соответствии с этой статьей, и это все еще повторный рендеринг

 const mapDispatchToProps = {
    resetWorkouts
};
  

Ответ №1:

это потому, что react выполняет неглубокое сравнение между prevProps и nextProps, и вы можете контролировать это только в shouldComponentUpdate , react не знает, что диспетчер тот же, что и при предыдущем рендеринге, потому что вы используете return внутри mapDispatchToProps функции. В вашем компоненте и в вашем случае, хотя функция останется прежней, вы можете выбрать два пути:

путь 1:

переопределите shouldComponentUpdate перехват жизненного цикла следующим образом:

 shouldComponentUpdate(){
return false;
}
  

путь 2:

избавьтесь от возврата внутри mapDispatchToProps и упростите подключение, чтобы оно было следующим:

 `conncect(state => ({}), {
        resetWorkouts: resetWorkouts})(YourComponent);`
  

использование одного из приведенных выше путей должно помочь вам

Комментарии:

1. В Path2 я не могу скомпилировать без return внутри mapDispatchToProps. Он показывает ошибку -> Ожидал назначения или вызова функции, а вместо этого увидел выражение. Я не мог найти никакого использования без return подключения к Redux

2. Я обновил свой комментарий, извините, я не привык использовать mapDispatchToProps , я надеюсь, что обновление решит вашу проблему

3. Очень странно, что … если мой AboutPage React-Router <Route> включен, он продолжает повторный рендеринг снова и снова. Если я закомментировал эту строку в своих маршрутах и использую AboutPage ее как component в другом компоненте, она отображается только один раз.

4. да, я вижу, проблема здесь в том, чтобы PureComponents провести неглубокое сравнение между previous props и next props , и это не проблема только с вашим About компонентом, то же самое и с вашим showConter , если вы зарегистрировали реквизиты одного из ваших компонентов, вы можете увидеть, как реквизит истории, полученный из Route компонента, который содержитсложные данные, которые не передаются при поверхностном сравнении, поэтому react будет обновлять компонент все больше и больше.

5. предыдущий комментарий должен был показать вам проблему, теперь ответ на ваш вопрос заключается в том, что react не отображает все JSX в функции рендеринга, при каждом рендеринге react делает снимок того, как JSX выглядит дерево, прежде чем применять изменения к dom, снимок является подробным,в отличие от неглубокого сравнения, поэтому, когда react снова пришел для повторного рендеринга ShowCounter компонента, он заметил, что About компонент все еще находится в том же месте и имеет то же дерево, поэтому он не будет повторно отображать его, это то, что virtual dom получил в качестве преимущества, надеюсь, это ответ на ваш вопрос.

Ответ №2:

Причина, по которой ваш компонент рендерится, заключается в том, что каждый раз выполняется следующая функция:

 const mapDispatchToProps = dispatch => {
    return {
        resetWorkouts: () => dispatch(resetWorkouts())
    }
}
  

ваши компоненты получают новый экземпляр свойства с именем resetWorkouts (потому что вы создаете встроенную функцию массива). Вы можете посмотреть ownProps , чтобы проверить, есть ли у вашего компонента resetWorkouts :

 const mapDispatchToProps = (dispatch, ownProps) => {
    return {
        resetWorkouts: ownProps.resetWorkouts || () => dispatch(resetWorkouts())
    }
}