React 和 jquery-ui/ui/widgets/sortable:子组件不会按预期重新排序



我在父组件的"状态"中有一个名为"投资组合"的数组。您可以使用:"this.state.portfolios"进行访问。

以及一个名为"StockDetailsComponent"的子组件。

在父组件中,我使用 map 函数来渲染子组件"StockDetailsComponent",如下所示:

{
this.state.portfolios.map((obj, key) => {
return <StockDetailsComponent key={key} portfolio={obj} onRemovePortfolio={this.onRemovePortfolio}/>;
})
}

还行。但是当我重新排序"this.state.portfolios"时,子组件重新渲染不符合预期。

之前:投资组合 = ["object_stock_symbol_1"、"object_stock_symbol_2"];

重新订购后:投资组合 = ["object_stock_symbol_2"、"object_stock_symbol_1"];

父组件如下所示,让我解释一下:

class VndDomain extends React.Component {
constructor(props) {
super(props);
this.socket = null;
this.sortableEnabled = false;
this.state = {
portfolios: []
};
}
render() {
return (
<div id="SQ-vnd">
<HeaderComponent/>
<div className="SQ-body">
<div className="SQ-text-right">
<p className="SQ-d-inline-block SQ-cursor-pointer SQ-mt-5 SQ-mb-5" onClick={this.removeAllPortfolios}>Xóa toàn bộ</p>
</div>
<StockFormCreateComponent onCreatePortfolio={this.onCreatePortfolio}/>
<div id="JSSQ-portfolio">
{
this.state.portfolios.map((obj, key) => {
return <StockDetailsComponent key={key} portfolio={obj} onRemovePortfolio={this.onRemovePortfolio}/>;
})
}
</div>
</div>
<FooterComponent/>
</div>
);
}
componentDidMount() {
this.enableSortable();
this.getAllPortfolioByUserId();
}
/**
* Get all portfolios belong to current user
* @return {Promise} [description]
*/
getAllPortfolioByUserId = async () => {
try {
this.props.dispatch(loadingSpinnerActions.showLoadingSpinner());
let result = await PortfolioService.getAllPortfolioByUserId();
if(result.data.status === "SUCCESSFUL") {
this.setState({portfolios: result.data.data}, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});
} else {
throw new Error(`${result.data.message}`);
}
} catch(error) {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
CommonUtilities.ShowLog(error.message);
}
}
/**
* Enable drag and drop to reorder
* @return {[type]} [description]
*/
enableSortable = () => {
let parentEl = $("#JSSQ-portfolio");
// Check duplicate sortable before set
if (this.sortableEnabled) {
parentEl.sortable("destroy");
parentEl.sortable();
} else {
parentEl.sortable();
this.sortableEnabled = true;
}
parentEl.on("sortupdate", async () => {
let sorted = parentEl.sortable("serialize");
let newOrderArrObj = sorted.split("&").map((value) => {
let symbol = value.replace("SQ[]=", "").toUpperCase();
let portfolio = this.state.portfolios.find(obj => obj.symbol === symbol);
return {
_id: portfolio._id,
symbol
};
});
try {
this.props.dispatch(loadingSpinnerActions.showLoadingSpinner());
let result = await PortfolioService.reorderPortfolio({newOrder: newOrderArrObj});
if(result.data.status === "SUCCESSFUL") {
this.setState({portfolios: result.data.data}, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});
} else {
throw new Error(`${result.data.message}`);
}
} catch(error) {
this.setState((prevState) => {
return {portfolios: prevState.portfolios};
}, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});
}
});
}

首先,我从数据库中获取投资组合列表,分配给状态的"投资组合",显示在客户端中。并启用拖放以通过"启用可排序"功能重新排序。目前,它工作正常。

当我拖动以重新排序时,"this.state.portfolios"按预期更改,我可以在"console.log(("中看到,但子组件渲染是错误的。不是顺序。

代码很长,所以你只需要注意我尝试过的以下选项: 选项 1:

this.setState({portfolios: result.data.data}, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});

result.data.data是重新排序后的数据,它很好,但重新渲染不能按顺序工作。

选项2:如果我通过空数组清除状态并像下面的代码一样再次设置它,这是有效的,因为子组件已被"卸载"并重新渲染,而只是像选项 1 一样更新。

this.setState({portfolios: []}, () => {
this.setState({portfolios: result.data.data}, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});
});

请帮我:(我不想设置状态,然后再次设置状态。

看起来你的投资组合数据是一个复杂的对象,React 无法确定它已经发生了变化。Yoiu可以像下面这样做:

你可以这样做:

let newPrtfolio = Object.assign ([],result.data.data); // Assign data to new object and assign it
this.setState({portfolios: newPrtfolio }, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});

或者,如果您的投资组合是一个对象而不是数组,那么您可以尝试以下方式:

let newPrtfolio = Object.assign ({},result.data.data); // Assign data to new object and assign it

this.setState({portfolios: newPrtfolio }, () => {
this.props.dispatch(loadingSpinnerActions.hideLoadingSpinner());
});

您可以尝试这两种方法,其中一种将根据您的投资组合对象的结构为您解决

最新更新