在渲染组件之前清除特定的 redux 状态
Clearing specific redux state before rendering component
我有以下 "Buy" 购物车按钮。
我还有一个名为 Tooltip 的组件,它会在 error/success 消息时自行显示。它使用按钮的宽度来确定它的中心点。因此,我使用 `ref 因为我需要在 DOM 内访问它的物理大小。我读到使用 ref 属性是个坏消息,但我不确定如何定位基于物理 DOM 的子组件。但那是另一个问题... ;)
我将应用程序的状态保存在 localStorage 中。如这里所见:
https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage
我 运行 遇到的问题是我必须在渲染之前清除状态 success
属性。否则,如果我在状态中有一条成功消息,在初始 render() 上 Tooltip
也会尝试渲染。这是不可能的,因为它所依赖的按钮还不在 DOM.
中
我认为通过 componentWillMount
中的 Redux 操作清除成功状态会清除成功状态,从而解决问题,但 render() 方法似乎无法识别该状态已更改,仍将显示 console.log() 中的旧值。
我的解决方法是检查按钮是否存在以及成功消息:showSuccessTooltip && this.addBtn
为什么 render() 无法识别 componentWillMount() 状态变化?
这里是 ProductBuyBtn.js class:
import React, { Component } from 'react';
import { connect } from 'react-redux'
// Components
import Tooltip from './../utils/Tooltip'
// CSS
import './../../css/button.css'
// State
import { addToCart, clearSuccess } from './../../store/actions/cart'
class ProductBuyBtn extends Component {
componentWillMount(){
this.props.clearSuccess()
}
addToCart(){
this.props.addToCart(process.env.REACT_APP_SITE_KEY, this.props.product.id, this.props.quantity)
}
render() {
let showErrorTooltip = this.props.error !== undefined
let showSuccessTooltip = this.props.success !== undefined
console.log(this.props.success)
return (
<div className="btn_container">
<button className="btn buy_btn" ref={(addBtn) => this.addBtn = addBtn } onClick={() => this.addToCart()}>Add</button>
{showErrorTooltip && this.addBtn &&
<Tooltip parent={this.addBtn} type={'dialog--error'} messageObjects={this.props.error} />
}
{showSuccessTooltip && this.addBtn &&
<Tooltip parent={this.addBtn} type={'dialog--success'} messageObjects={{ success: this.props.success }} />
}
</div>
);
}
}
function mapStateToProps(state){
return {
inProcess: state.cart.inProcess,
error: state.cart.error,
success: state.cart.success
}
}
const mapDispatchToProps = (dispatch) => {
return {
addToCart: (siteKey, product_id, quantity) => dispatch(addToCart(siteKey, product_id, quantity)),
clearSuccess: () => dispatch(clearSuccess())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductBuyBtn)
好吧,这似乎是一个已知的问题,很容易进入(更难摆脱,尤其是以一种不错的/非 hacky 的方式。参见 this super-long thread)。
问题在于,在 componentWillMount
中调度一个动作(最终)改变了进入组件的道具并不能保证该动作之前已经发生第一个渲染。
所以基本上 render()
不会等待你发送的动作生效,它渲染一次(使用旧的道具),然后动作生效并改变道具和 然后 组件使用新道具重新渲染。
所以你要么必须做你已经做的事情,要么使用组件内部状态来跟踪它是否是第一次渲染,比如 this comment。列出了更多建议,但我无法一一列举。
我有以下 "Buy" 购物车按钮。
我还有一个名为 Tooltip 的组件,它会在 error/success 消息时自行显示。它使用按钮的宽度来确定它的中心点。因此,我使用 `ref 因为我需要在 DOM 内访问它的物理大小。我读到使用 ref 属性是个坏消息,但我不确定如何定位基于物理 DOM 的子组件。但那是另一个问题... ;)
我将应用程序的状态保存在 localStorage 中。如这里所见: https://egghead.io/lessons/javascript-redux-persisting-the-state-to-the-local-storage
我 运行 遇到的问题是我必须在渲染之前清除状态 success
属性。否则,如果我在状态中有一条成功消息,在初始 render() 上 Tooltip
也会尝试渲染。这是不可能的,因为它所依赖的按钮还不在 DOM.
我认为通过 componentWillMount
中的 Redux 操作清除成功状态会清除成功状态,从而解决问题,但 render() 方法似乎无法识别该状态已更改,仍将显示 console.log() 中的旧值。
我的解决方法是检查按钮是否存在以及成功消息:showSuccessTooltip && this.addBtn
为什么 render() 无法识别 componentWillMount() 状态变化?
这里是 ProductBuyBtn.js class:
import React, { Component } from 'react';
import { connect } from 'react-redux'
// Components
import Tooltip from './../utils/Tooltip'
// CSS
import './../../css/button.css'
// State
import { addToCart, clearSuccess } from './../../store/actions/cart'
class ProductBuyBtn extends Component {
componentWillMount(){
this.props.clearSuccess()
}
addToCart(){
this.props.addToCart(process.env.REACT_APP_SITE_KEY, this.props.product.id, this.props.quantity)
}
render() {
let showErrorTooltip = this.props.error !== undefined
let showSuccessTooltip = this.props.success !== undefined
console.log(this.props.success)
return (
<div className="btn_container">
<button className="btn buy_btn" ref={(addBtn) => this.addBtn = addBtn } onClick={() => this.addToCart()}>Add</button>
{showErrorTooltip && this.addBtn &&
<Tooltip parent={this.addBtn} type={'dialog--error'} messageObjects={this.props.error} />
}
{showSuccessTooltip && this.addBtn &&
<Tooltip parent={this.addBtn} type={'dialog--success'} messageObjects={{ success: this.props.success }} />
}
</div>
);
}
}
function mapStateToProps(state){
return {
inProcess: state.cart.inProcess,
error: state.cart.error,
success: state.cart.success
}
}
const mapDispatchToProps = (dispatch) => {
return {
addToCart: (siteKey, product_id, quantity) => dispatch(addToCart(siteKey, product_id, quantity)),
clearSuccess: () => dispatch(clearSuccess())
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ProductBuyBtn)
好吧,这似乎是一个已知的问题,很容易进入(更难摆脱,尤其是以一种不错的/非 hacky 的方式。参见 this super-long thread)。
问题在于,在 componentWillMount
中调度一个动作(最终)改变了进入组件的道具并不能保证该动作之前已经发生第一个渲染。
所以基本上 render()
不会等待你发送的动作生效,它渲染一次(使用旧的道具),然后动作生效并改变道具和 然后 组件使用新道具重新渲染。
所以你要么必须做你已经做的事情,要么使用组件内部状态来跟踪它是否是第一次渲染,比如 this comment。列出了更多建议,但我无法一一列举。