prevProps и this.props всегда будут возвращать одно и то же значение в componentDidUpdate при использовании response-redux - PullRequest
0 голосов
/ 07 февраля 2020

Когда пользователь нажимает на ссылку «Войти» в навигации, на странице отображается модальный режим. Навбар и модал содержатся в компоненте AppHeader. Другой компонент с именем ActionBar также имеет кнопку входа. Поэтому я использовал react-redux для связи между различными компонентами. Вот моя реализация. (store.js опущено.)

actionTypes. js

export const LOGIN_FORM_SHOW = 'LOGIN_FORM_SHOW'

действия. js

import { LOGIN_FORM_SHOW } from './actionTypes'
export const loginFormShow = () => ({
   type: LOGIN_FORM_SHOW,
   payload: {}
})

редуктор. js

import { LOGIN_FORM_SHOW } from './actionTypes'
const defaultState = { 
  loginFormVisible: false 
}
export default function(state = defaultState, action) {
  switch(action.type) {
    case LOGIN_FORM_SHOW: {
      return { 
        ...state,
        loginFormVisible: true 
      }
    }
  }
}

AppHeader. js

import React from 'react'
import LoginModal from '../components/LoginModal'
import {authService} from 'services/auth'
import { connect } from 'react-redux'
import {loginFormShow} from "../../redux/actions"

class AppHeader extends React.PureComponent {
  constructor(props) {
    super(props)
    this.state = {
      loginFormVisible: this.props.loginFormVisible ? true : false
    }
    this.showLoginModal = this.showLoginModal.bind(this)
  }
  showLoginModal() {
    this.setState({
      loginFormVisible: true
    })
  }
  componentDidUpdate(prevProps, prevState, snapshot) {
    if(this.props.loginFormVisible) {
      this.showLoginModal()
    }
  }
  render() {
    return (
      <>
        // ... rest omitted
        <nav><ul>
          <li onClick={this.showLoginModal}>Login</li>
        </ul></nav>
        // ... ... ...
        <LoginModal 
          open = {this.state.loginFormVisible}
          onClose = { () => { this.setState(loginFormVisible: false) } }
        />  
      </>
    )
  }
}

const mapStateToProps = (state) => {
  return {
    loginFormVisible: state.loginFormVisible
  }
}

export default connect(
  mapStateToProps, 
  null
)(AppHeader)

ActionBar. js

import React from 'react'
import {loginFormShow} from "../../redux/actions"
import {connect} from "react-redux"

class ActionBar extends React.Component{
  render() {
    return (
      <button onClick={this.props.loginFormShow}>Log In</button>
    )
  }
}

export default connect(
  null,
  { loginFormShow }
)(ActionBar)

Кнопка входа в систему AppHeader работает нормально. Но кнопка в ActionBar показывает проблему.

Когда модальное имя входа отображается после нажатия кнопки в ActionBar. Вы не можете закрыть модальный логин, потому что будет вызван метод componentDidUpdate, а props.loginFormVisible будет всегда возвращать true .

Поскольку react-redux доставляет состояние магазина как реквизиты, вы не можете изменить реквизит. Таким образом, вы не можете сказать, был ли обработан запрос от ActionBar, и можно ли закрыть модальный вход prevProps и props всегда будут одинаковыми после первого нажатия кнопки в ActionBar.

Я могу определить другой actionType LOGIN_FORM_CLOSE и исправить эту проблему, но я думаю, что там лежит некоторые ограничения из react-redux.

Без использования actionType LOGIN_FORM_CLOSE мой обходной путь следующий:

AppHeader. js

componentDidUpdate(prevProps, prevState, snapShot) {
  if((!prevProps.lastHandled || (this.props.lastHandled - prevProps.lastHandled)) && this.props.loginFormVisible) {
    this.showLoginModal()
  }
}
// ....
const mapStateToProps = (state) => {
  const props = { loginFormVisible: state.loginFormVisible }
  if (state.loginFormVisible) {
    props.lastHandled= (new Date).getTime()
  }
}

Почему react-redux только отображает состояние магазина в реквизит? Вы не можете получить доступ к состоянию компонента в mapStateToProps. Мне трудно пользоваться.

1 Ответ

1 голос
/ 07 февраля 2020

Вам не нужно ваше componentDidUpdate. Вы можете условно визуализировать ваш компонент на основе this.props.loginFormVisible

  render() {
    return (
      <>
        // ... rest omitted
        <nav><ul>
          <li onClick={this.showLoginModal}>Login</li>
        </ul></nav>
        // ... ... ...
        {this.props.loginFormVisible && <LoginModal 
          open = {this.state.loginFormVisible}
          onClose = { () => { this.setState(loginFormVisible: false) } }
        /> } 
      </>
    )
  }
}

Это простой способ уменьшить помехи от вашего componentDidUpdate. Вы также можете избавиться от своей open опоры и упростить вещи.

Redux хорош при попытке синхронизировать состояние между компонентами. Поскольку вы находитесь в ситуации, когда вам нужно совместно использовать состояние по крайней мере для двух компонентов, и оба этих компонента должны иметь возможность изменять и / или читать состояние, я бы рекомендовал сохранять loginFormVisible в состоянии вашего магазина. Я прочитал бы это как опору в обоих компонентах, и только изменил бы это через действия. Так что создание действия LOGIN_FORM_CLOSE - отличная идея. Всякий раз, когда у вас есть строка типа this.state = { loginFormVisible: this.props.loginFormVisible ? true : false }, вам нужно пересмотреть, где вы хотите, чтобы ваш штат жил. В вашем случае, вероятно, лучше управлять этим магазином в магазине.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...