首页 > 解决方案 > 如何将本地 setState 列表与 Redux 列表合并为一个列表 - redux react

问题描述

在这里,我遇到了一个困难的情况。我在JobsPanel组件中有一个 locationData json,它基于一个 id(jobId) 保存位置详细信息。现在,在我的组件中,我有一个“配置位置”部分,我在其中调用保存的位置数据并从该 json 创建一个 setState 列表(“configuredList”)。现在,我在我的应用程序初步位置数据中多了一个部分,使用 redux 操作调用其他 api 并保存到列表“conLocations”中。

现在,我将一个位置项“conLocation”列表(redux 状态)添加到“configuredList”(setState)并更新更改。它工作正常,但最后添加的项目显示两次。经过试用,我明白我已经渲染了两个映射列表。如何将其合并为一个?到目前为止,我已经做到了这一点。

configLocation 函数,我从 locationData json 检索上次保存的位置。

/** Currently initialize and configure configuredList for retrieving existing job's location data */
   configLocation(locationData) {
    let configuredList = [];
    if (locationData.locations.locationDetails != null && locationData.locations.locationDetails != undefined) {
        locationData.locations.locationDetails.map(item => {
            let listitem = { ...item };
            configuredList.push(listitem);
        });
    }
    this.setState({ configuredList });
}

getLocationData 函数,我正在合并两个检索列表和 conLocations 列表的列表,并且我将此函数调用到正在发生保存更改或更新更改操作的其他组件。它工作正常。

getLocationData() {
        let saveableLocationlist = [];
        if (this.props.conLocations != null && this.state.configuredList != null) {
            const { configuredList } = this.state;
            const { conLocations } = this.props;
            let totalList = configuredList.concat(conLocations);
            saveableLocationlist = totalList;
        }
        const locationData = {
            locationDetails: saveableLocationlist
        }
        return locationData;
    }

在这里你可以看到我正在更新 locationData json。通过在作业面板中调用此函数,更新的 locationData json 现在可用于我的“configLocation”函数中的组件。

我的组件代码:

export class NewLocationPanel extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            open: false,
            configuredList: [],
            chkitems: []
        };
        this.configLocation = this.configLocation.bind(this);
        this.togglePanel = this.togglePanel.bind(this);
        this.handleClick = this.handleClick.bind(this);
        this.allLocations = this.allLocations.bind(this);
        this.clearall = this.clearall.bind(this);
        this.getLocationData = this.getLocationData.bind(this);
        this.handleRemove = this.handleRemove.bind(this);
        this.removeConfigLocation = this.removeConfigLocation.bind(this);
        this.removeLocationAll = this.removeLocationAll.bind(this);
        this.handleChecklocation = this.handleChecklocation.bind(this);
        this.handleCheckedAdded = this.handleCheckedAdded.bind(this);
        this.handleCheckedRemove = this.handleCheckedRemove.bind(this);
        this.handleActionButton = this.handleActionButton.bind(this);
    }


    componentDidMount() {
        this.props.loadData();
        if (this.props.locationData != null && this.props.locationData != undefined) {
            this.configLocation(this.props.locationData);
        }
    }
    componentDidUpdate(prevProps, prevState) {
        if ((prevProps.jobId != this.props.jobId || prevProps.locationData != this.props.locationData)) {
            this.configLocation(this.props.locationData);
        }
    }

//other codes

   /** Currently initialize and configure configuredList for retrieving existing job's location data */
   configLocation(locationData) {
    let configuredList = [];
    if (locationData.locations.locationDetails != null && locationData.locations.locationDetails != undefined) {
        locationData.locations.locationDetails.map(item => {
            let listitem = { ...item };
            configuredList.push(listitem);
        });
    }
    this.setState({ configuredList });
}


    /** updating locationData by saving changes - calling this function into jobsPanel */
    getLocationData() {
        let saveableLocationlist = [];
        if (this.props.conLocations != null && this.state.configuredList != null) {
            const { configuredList } = this.state;
            const { conLocations } = this.props;
            let totalList = configuredList.concat(conLocations);
            saveableLocationlist = totalList;
        }
        const locationData = {
            locationDetails: saveableLocationlist
        }
        return locationData;
    }

    //other codes

    render() {
        //const{configuredList} = this.state;
        const _labels = store.getLabels();
        let collapsedToggle = this.props.open ? 'collapsed' : ''
        return (

                {this.state.open ? (
                    <div className="panel-body">
                        <div className="row grid-divider">
                            <div className="col-sm-6">
                                <div className="col-padding">
                                    <div className="pos-div"><h4>Configured Location</h4>
                                    <div><table className="table configTableColor"><thead>{this.state.configuredList.map((locc, index) => <tr key={index}><th><input type="checkbox" onClick={() => this.handleCheckedRemove(locc.mruCode)} /><label></label></th><th className="configLocationInfo">{locc.mruCode} - {_labels[locc.division]} - {locc.country}</th><th className="text-right"><img alt="DeleteIcon" onClick={() => { this.removeConfigLocation(index) }} className="deleteIconStyle" src="img/delete_large_active.png" /></th></tr>)}</thead>



<tbody>
                                        {this.props.conLocations.map((loct, index) => <tr key={index}>
                                            <td><input type="checkbox" /><label></label></td>
                                            <td className="configLocationInfo">{loct.mruCode} - {_labels[loct.division]} - {loct.country}</td>
                                            <td className="text-right"><img alt="DeleteIcon" onClick={() => this.handleRemove(loct.mruCode)} className="deleteIconStyle" src="img/delete_large_active.png" /></td>
                                        </tr>
                                        )}
                                    </tbody></table></div>

                                </div>
                            </div>
                        </div>
                    </div>) : null}
            </div>

        );
    }
}

const mapStateToProps = state => {
    return {
        location: state.locationRed.location,
        conLocations: state.locationRed.conLocations,
        isChecked: state.locationRed.isChecked
    };
};

const mapDispatchToProps = (dispatch) => {
    return {
        loadData: () => { dispatch(loadData()) },
        addLocation: (mruCode) => { dispatch(addLocation(mruCode)) },
        addAllLocation: () => { dispatch(addAllLocation()) },
        removeLocation: (mruCode) => { dispatch(removeLocation(mruCode)) },
        removeAllLocation: () => { dispatch(removeAllLocation()) },
        checkboxState: (mruCode) => { dispatch(checkboxState(mruCode)) },
        checkedLocation: () => { dispatch(checkedLocation()) }
    }
}


export default connect(mapStateToProps, mapDispatchToProps, null, { withRef: true })(NewLocationPanel);

如您所见,我正在渲染两个列表。如何合二为一?

我正在初始化和保存 locationData 详细信息的作业面板组件

import React from 'react';
import ReactDOM from 'react-dom';
import LocationPanel from '../panels/NewLocationPanel';

class JobsPanelComponent extends React.Component {

    constructor(props) {
        super(props);
        this.state = { 
            jobDetailJson: this.props.jobDetailJson

        };
this.setLocationPanelRef = cRef =>{this.locationPanel = cRef;};

}
componentWillUnmount() {
        this.clearStates();
        this.clearRefs();
        this.clearBindings();
    }
          clearStates() {

        this.state.jobDetailJson = null;
        }
        clearRefs(){
               this.locationPanel = null;
                   }
        clearBindings(){
               this.setLocationPanelRef = null;
                       }
        componentWillMount() {
        this.state.jobDetailJson = this.props.jobDetailJson;
    }

    componentWillReceiveProps(nextProps) {
        this.state.jobDetailJson = nextProps.jobDetailJson;
    }
     saveJobData(jobData){
      var locationData = null;
       if(some conditions){
        locationData = this.locationPanel.getWrappedInstance().getLocationData();
      }
    //more other lines not related to my mine
     }
      render(){
         var locationDataJson= null;
             if(this.state.jobDetailJson != null){
                     locationDataJson =this.state.jobDetailJson;
                   }
         return(<div className="panel-group" id="jobsPanelGroup">
               <LocationPanel ref={this.setLocationPanelRef} locationData ={locationDataJson} jobDetailJson={this.state.jobDetailJson} versionId={versionId} jobName={jobName} jobId={jobId} isForViewOnly={this.props.isForViewOnly} parentJobId={this.props.parentJobId} title="Location"/>
     //More coded lines for other things not related to my part
              );
         }


}

我的应用程序流程将类似于 - 配置位置(初始)配置列表 -> 配置位置(redux 列表) -> 配置位置(添加项目) -> 配置位置(中间)配置列表 + 添加项目(配置位置) -> 保存更改 -> 配置位置( final) - 合并列表

保存更改/更新 locationData 一切都在工作面板中,但工作正常。没有问题。如何在我的组件中进行更改。

标签: javascriptreactjsreduxreact-redux

解决方案


mapStateToProps函数同时传递了 redux 状态组件的 props。所以你可以将你的位置从 redux 和里面的 props 组合起来mapStateToProps

// destructuring only the things we need from state (locationRed) and props (locationData)
const mapStateToProps = ({ locationRed }, { locationData }) => ({
  location: locationRed.location,
  // get a merged set
  conLocations: [...locationRed.conLocations, ...(locationData.locations.locationDetails || [])],
  isChecked: locationRed.isChecked
})

使用此设置,您很可能会消除您的configuredList状态和相关的更新函数,您的componentDidUpdate函数只是从两个单独的循环中渲染props.conLocations而不是从状态和道具。

mapStateProps在合并列表时,您还可以对位置进行重复数据删除或在其中进行所需的任何工作 ID 检查。如果mapStateToProps.


推荐阅读