#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
подключения к Redux2. Я обновил свой комментарий, извините, я не привык использовать
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())
}
}