javascript - 使用react-redux时,prevProps和this.props将始终在componentDidUpdate中返回相同的值

标签 javascript reactjs redux react-redux

当用户单击导航中的“登录”链接时,页面会显示一个模式。导航栏和模式包含在 AppHeader 组件中。 另一个名为 ActionBar 的组件也有一个登录按钮。所以我使用react-redux在不同组件之间进行通信。 这是我的实现。 (store.js 被省略。)

actionTypes.js

export const LOGIN_FORM_SHOW = 'LOGIN_FORM_SHOW'

actions.js

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

reducer.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 将存储状态作为 props 提供,因此您无法修改 props。因此,您无法判断来自 ActionBar 的请求是否已实际处理,并且可以关闭登录模式。在 ActionBar 中第一次单击按钮后,prevPropsprops 将始终相同。

我可以定义另一个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只将存储状态映射到 Prop ?您无法在 mapStateToProps 中访问组件的状态。我觉得很难用。

最佳答案

您不需要 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 在尝试同步组件之间的状态时非常有用。因为您处于需要在至少 2 个组件之间共享状态的情况,并且这两个组件都需要能够更改和/或读取状态,所以我建议将 loginFormVisible 保留在您的商店的状态。我会将其视为两个组件中的 Prop ,并且仅通过操作来更改它。因此,执行 LOGIN_FORM_CLOSE 操作是个好主意。每当你有像 this.state = { loginFormVisible: this.props.loginFormVisible ? true : false },您需要重新考虑您希望状态存在的位置。就您而言,对于这个状态,它可能更好地完全在商店中管理。

关于javascript - 使用react-redux时,prevProps和this.props将始终在componentDidUpdate中返回相同的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60119675/

相关文章:

javascript - $(document).click() 在 iPhone 上无法正常工作。查询

javascript - 如何检查单击的元素是否与 React 中的 onClick 事件相同?

reactjs - 相当于 PropTypes.arrayOf 的 TypeScript 声明是什么?

node.js - Redux - 通过键在状态数组中查找对象并更新其另一个键

javascript - Redux以前的状态已经有了新的状态值无法理解为什么

javascript - react 和 Redux : Dispatching action not working

javascript - 获取 CSS 值并将其更新为 SQL

javascript - 将局部变量传递给 AngularJs 中的指令

asp.net - window.showModalDialog dialogWidth 属性在 IE 中不起作用

javascript - 无状态 React 组件是否可以进行 CSS 转换?