【问题标题】:Component doesn't re-render after state changes状态更改后组件不会重新渲染
【发布时间】:2019-06-29 02:49:48
【问题描述】:

我有一个包含两组按钮(功能和目标)的界面。当我单击一个按钮时,我希望它从一个团队转到另一个团队。我正在使用 react 和 redux 来实现这一点。我唯一的问题是,当状态更新并且我成功控制台记录更新状态时,组件不会,除非我使用 forceUpdate()。我不明白的是,既然状态更新成功,组件不应该自动重新渲染吗?

一些.js

class Some extends React.Component{

    constructor(props){
        super(props)
        this.state = {
            selectedFeatures:[],
            selectedTargets:[]
        }
    }

    setStateFromProps(){
        this.setState({
            selectedFeatures: this.props.features,
            selectedTargets: this.props.targets,
        }, console.log(this.state.selectedFeatures, this.state.selectedTargets))
    }

    componentDidMount(){
        this.setStateFromProps()
    }

    render(){

        const { features, targets} = this.props

        const updateLists =(selectedFeature, flag) =>{
            let index
            if  (flag){
                index = features.indexOf(selectedFeature)
                features.splice(index, 1);

                targets.push(selectedFeature)

                this.props.addFeature({features, targets})
            }else{
                index = targets.indexOf(selectedFeature)
                targets.splice(index, 1);

                features.push(selectedFeature)
                this.props.addFeature({targets, features})
            }

            console.log(this.state.selectedFeatures, this.state.selectedTargets)


        }

        return (
            <div>
                {this.state.selectedFeatures.map(feature => {

                    return <div><button key={feature} onClick={() => updateLists(feature, true)}>{feature}</button> <br /></div>
                })}
                <br />
                {this.state.selectedTargets.map(target => {
                    return <div><button key={target} onClick={() =>updateLists(target, false)} >{target}</button> <br /></div>
                })}
            </div>
        );

    }
}

const mapDispatchToProps =(dispatch) =>{
    return {
            addFeature: (data) => dispatch(featureAddedToTargets(data)),
        }
} 
const mapStateToProps= (state)=>{
    return { selectedFeature:state.addFeatureReducer.selectedFeature,
            features: state.addFeatureReducer.features,
            targets: state.addFeatureReducer.targets
    };
}


export default connect(mapStateToProps, mapDispatchToProps)(Some);

如您所见,当我点击一个按钮时,我触发了 updateLists 函数,该函数将使计算更改发送到我们唯一的操作,带有更新的功能和目标按钮的新数据,并且该操作将更改状态减速机。

featureAddedToTargets 操作

    export const featureAddedToTargets = (data) =>{
        return {
            type: FEATURE_CHANGED,
            data
        }
    }

addFeatureReducer

    const initialState = {
        features:['f1','f2','f3','f4','f5'],
        targets:['t1','t2']
    }

    const addFeatureReducer = (state=initialState, action) =>{
        switch(action.type){
            case FEATURE_CHANGED:
                console.log("action: ", action)
                return {...state , state, features: action.data.features, targets: action.data.targets};
            default: 
                return state;
        }
    }
export default combineReducers({ addFeatureReducer })

正如我所说,Some 组件不会重新渲染,并且按钮组保持不变,即使 reducer 中的 initialState 已更改,因此 Some 组件中的 props 也已更改。我想了解为什么会这样。

enter image description here

【问题讨论】:

    标签: reactjs redux


    【解决方案1】:

    在你触发一个动作FEATURE_CHANGED 之后,你的reducer 将返回一个更新的状态,该状态又通过mapStateToProps 作为newProps 传播到你的React 组件。在渲染函数中,您正在映射this.state.selectedFeaturesthis.state.selectedTargets。据我所知,虽然你得到了 newProps featurestargets,但你并没有在组件的状态下更新它们。您可以使用getDerivedStateFromProps 生命周期在新道具到达时更新状态。

    getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.features !== prevState.features && nextProps.targets !== prevState.targets) {
            return ({
               selectedFeatures: nextProps.features,
               selectedTargets: nextProps.targets
            });
        }
        else if (nextProps.features !== prevState.features) {
           return ({
               selectedFeatures: nextProps.features,
            });
        } else if (nextProps.targets !== prevState.targets) {
           return ({
               selectedTargets: nextProps.targets,
            });
        }
    }
    

    您可以在这里参考:https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops

    【讨论】:

    • 这不起作用,我想知道因为我之前遇到过这个问题,所以我在调试器和 console.log 中遵循组件的状态以及它打印的内容,状态似乎正确更新。尽管组件没有重新渲染,但功能和目标仍然保留给他们原来的团队。如果我在 updateLists() 结束时执行 forceUpdate() ,那么只有这样组件才会呈现更新状态。但我不想手动更新组件,因为它应该自动重新渲染。
    【解决方案2】:
    setStateFromProps(){
            this.setState({
                selectedFeatures: this.props.features,
                selectedTargets: this.props.targets,
            }, console.log(this.state.selectedFeatures, this.state.selectedTargets))
        }
    

    尝试将其更改为

        componentDidUpdate(prevProps) {
            if(this.props.features !== prevProps.features || this.props.targets !== prevProps.targets) {
          this.setState({
                selectedFeatures: this.props.features,
                selectedTargets: this.props.targets,
            }, console.log(this.state.selectedFeatures, this.state.selectedTargets))
        }
    
    }
    

    【讨论】:

      【解决方案3】:

      所以我想出了为什么即使状态正在更新,组件也没有更新。似乎在 updatedLists() 中,我直接在 redux 存储的特征和目标数组上使用了 push() 和 splice(),从而改变了我的状态。由于突变,组件没有看到当前和下一个状态的变化。 React 在内存中保存状态的两个版本——当前版本和下一个版本。它比较两者并仅使用已更改的部分更新 DOM。由于我正在改变状态,React 将 current 和 next 视为相同,因此它没有更新。所以我只是更改了 updatedLists(),我在随机变量(特征和目标)中应用了 push() 和 splice(),后来我将它们作为数据传递给我们的操作,使用扩展运算符(就像我们之前所做的那样)将它们的值传递到商店的状态(initialState)。

      if  (flag){
                  index = this.state.selectedFeatures.indexOf(selectedFeature)
                  const Features = [...this.state.selectedFeatures]
                  Features.splice(index, 1);
      
                  const Targets = [...this.state.selectedTargets]
                  Targets.push(selectedFeature)
      
                  console.log('features',features,'targets',targets)
                  this.props.addFeature({features: Features , targets: Targets})
              }else{
                  index = this.state.selectedTargets.indexOf(selectedFeature)
                  const Targets = [...this.state.selectedTargets]
                  Targets.splice(index, 1);
      
                  const Features = [...this.state.selectedFeatures]
                  Features.push(selectedFeature)
      
                  console.log('features',features,'targets',targets)
                  this.props.addFeature({ features:Features, targets: Targets})
              }
      

      【讨论】:

        猜你喜欢
        • 2019-06-17
        • 2019-07-30
        • 1970-01-01
        • 2021-05-19
        • 2022-01-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-10-06
        相关资源
        最近更新 更多