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

时间:2018-07-02 09:53:54

标签: javascript reactjs

我正在尝试构建onChange搜索功能。在建议列表中,我的状态如下:

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}});
};

4 个答案:

答案 0 :(得分:2)

    //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

答案 1 :(得分:1)

您可以找到要放在数组中的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>
    );
  }
} 

答案 2 :(得分:1)

首先,我们需要使用index找到一个findIndex,然后使用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);

答案 3 :(得分:0)

要将选定项移到第一位置,可以使用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>