React 和 jquery-ui/ui/widgets/sortable:子组件未按预期重新排序
React and jquery-ui/ui/widgets/sortable: Child component not reorder as expect
我在名为“portfolios”的父组件的“State”中有一个数组。您可以使用以下方式访问:“this.state.portfolios”.
还有一个名为“StockDetailsComponent”的子组件。
在父组件中,我使用映射函数来呈现子组件“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());
});
}
});
}
首先,我从数据库中获取投资组合列表,分配给客户端中显示的状态“投资组合”。并启用 drag/drop 通过“enableSortable”功能重新排序。此时,它工作正常。
当我拖动重新排序时,“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());
});
});
请帮帮我 :( 我不想先 setState 然后再 setState。
看起来您的投资组合数据是一个复杂的对象,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());
});
您可以尝试这两种方法,其中一种方法会根据您的投资组合对象的结构为您解决
我在名为“portfolios”的父组件的“State”中有一个数组。您可以使用以下方式访问:“this.state.portfolios”.
还有一个名为“StockDetailsComponent”的子组件。
在父组件中,我使用映射函数来呈现子组件“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());
});
}
});
}
首先,我从数据库中获取投资组合列表,分配给客户端中显示的状态“投资组合”。并启用 drag/drop 通过“enableSortable”功能重新排序。此时,它工作正常。
当我拖动重新排序时,“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());
});
});
请帮帮我 :( 我不想先 setState 然后再 setState。
看起来您的投资组合数据是一个复杂的对象,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());
});
您可以尝试这两种方法,其中一种方法会根据您的投资组合对象的结构为您解决