在 React 中更新状态:嵌套在 Object 中的数组元素



我正在尝试构建更改搜索功能。在建议列表中,我的状态是这样的:

results: {
page: 1,
results: [
{value: 'popularity.desc', label: 'Popularity Descending'},
{value: 'popularity.asc', label: 'Popularity Ascending'},
{value: 'new value', label: 'new label'},
{value: 'vote_average.desc', label: 'Rating Descending'}
]
}

当用户选取对象{value: 'new value', label: 'new label'}时。

如何将对象移动到状态数组results的第一个索引?

例如:选取对象后。状态应该是这样的:

results: {
page: 1,
results: [
{value: 'new value', label: 'new label'},
{value: 'popularity.desc', label: 'Popularity Descending'},
{value: 'popularity.asc', label: 'Popularity Ascending'},
{value: 'vote_average.desc', label: 'Rating Descending'}
]
}

我的想法是使用传播运算符和过滤器,但我不知道如何实现它。

选择项目方法:

onSuggestionSelected = (event, {suggestion, suggestionValue }) => {
console.log('Selected', suggestion);  // {value: 'new value', label: 'new label'}
if (suggestion.media_type === 'movie') {
this.navigate('/search/movie', suggestionValue, suggestion);
} else if (suggestion.media_type === 'tv') {
this.navigate('/search/tv', suggestionValue, suggestion);
} else {
this.navigate('/search', suggestionValue, suggestion);
}
};

选择后,它将导航:

navigate = (pathname, queryValue, resultValue) => {
// ResultValue is that Object that I want to shift first.
this.props.history.push({ 
pathname, 
search: `?query=${queryValue}`, 
state: {results: this.state.data}});
};
//filtered the remaining item
let remainValue = result.filter((obj, key) => obj.value != suggestion.value);
//merge here 
let newResult = [suggestion, ...remainValue]; //it will contain reordered item

首先我们需要使用findIndex找到一个index,然后filter当前状态以排除包含所选数据的对象。

我们需要做的最后一件事是使用扩展运算符...将结果合并到一个数组中。

例:

const currentState = [
{value: 'popularity.desc', label: 'Popularity Descending'},
{value: 'popularity.asc', label: 'Popularity Ascending'},
{value: 'new value', label: 'new label'},
{value: 'vote_average.desc', label: 'Rating Descending'}
];
const selectedValue = {value: 'new value', label: 'new label'};
const onSelectionChange = (selected) => {
const selectedIndex = currentState.findIndex(({ value }) => value === selected.value);
const selectedItem = currentState[selectedIndex];
const stateExcludedItem = currentState.filter(({ value }) => value !== selected.value);
const newState = [ selectedItem, ...stateExcludedItem ]

// this.setState
return newState;
}
const result = onSelectionChange(selectedValue);
console.log(result);

你可以找到要放在数组中第一个result的索引,然后把它放在第一位,然后是数组中result之前和之后的索引。

class App extends React.Component {
state = {
results: {
page: 1,
results: [
{ value: "popularity.desc", label: "Popularity Descending" },
{ value: "popularity.asc", label: "Popularity Ascending" },
{ value: "new value", label: "new label" },
{ value: "vote_average.desc", label: "Rating Descending" }
]
}
};
putResultFirst = result => {
this.setState(previousState => {
const { results } = previousState.results;
const resultIndex = results.indexOf(result);
return {
results: {
...results,
results: [
result,
...results.slice(0, resultIndex),
...results.slice(resultIndex + 1)
]
}
};
});
};
render() {
return (
<div>
{this.state.results.results.map(result => (
<div key={result.id} onClick={() => this.putResultFirst(result)}>
{result.value} {result.label}
</div>
))}
</div>
);
}
} 

若要将所选项移动到第一个位置,可以使用 Array.filter 方法将未选中项作为数组获取,并生成一个新的结果数组:

selectedItem = this.state.results.results[clickedIndex]
unselectedItems = this.state.results.results.filter((item, index) => clickedIndex !== index)

因为状态中的"结果"是一个对象。若要更新状态中的对象,应复制当前结果对象以创建新对象,以便更新状态。

results = {...this.state.results, results: [selectedItem, ...unselectedItems]}

您只想将所选项移动到结果数组的顶部,因此您只需将所选项的索引传输到事件处理程序,该处理程序将调用setState方法。

示例代码:

class App extends React.Component {
state = {
results: {
page: 1,
results: [
{value: 'popularity.desc', label: 'Popularity Descending'},
{value: 'popularity.asc', label: 'Popularity Ascending'},
{value: 'new value', label: 'new label'},
{value: 'vote_average.desc', label: 'Rating Descending'}
]
}
};
handelClick = (clickedIndex) => {
if(clickedIndex === 0) {
return;
}
let selectedItem = this.state.results.results[clickedIndex],
unselectedItems = this.state.results.results.filter((item, index) => clickedIndex !== index),
results = {...this.state.results, results: [selectedItem, ...unselectedItems]};
this.setState({results})
};
render() {
return <ul>
{this.state.results.results.map((item, index) =>
<li key={item.label} onClick={this.handelClick.bind('', index)}>{item.label}</li>)
}
</ul>
}
}
const renderFilterList = () => {
ReactDOM.render(<App />, document.getElementById('react-app'));
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="react-app"></div>

最新更新