在使用状态挂钩更新状态时,如何覆盖具有相同密钥的对象

时间:2020-02-18 14:52:29

标签: reactjs react-hooks react-functional-component use-state

我要在选择新过滤器时更新状态。初始状态显示了我想要的对象结构。例如,我添加了一个过滤器选择(例如“ f2”),每个过滤器的标签都是固定的,因此我们可以忽略它,但是值可能是“ va”。那很好,但是当我想将“ f2”的值更改为“ vb”时,我现在在状态{“ f2”:“ va”}和{“ f2”:“ vb”}中有两个条目,而我宁愿第一个覆盖第二个。

 const [filterValues, setFilterValues] = useState([{"f1":["l","v"]}]);

 const handleChange = (filter, label, value) => {
   setFilterValues([
     ...filterValues,
     {[filter]: [label, value]}
   ]);
 };

我尝试两次调用setFilterValues(一次将条目映射到我的条件)来解决问题,但是后来我什至根本没有更新状态:

 const handleChange = (filter, label, value) => {
    setFilterValues([
      ...filterValues,
      {[filter]: [label, value]}
    ]);
    let key = filter
    setFilterValues(
      filterValues.map(
        el => el.key == key?  { [key]: [label, value] } : el
      )
    )
  };

我有点新反应了,所以也许我对功能组件的状态更新没有什么基本了解。有人可以帮我吗?谢谢!

3 个答案:

答案 0 :(得分:0)

要做的方法是找到正确的对象并在设置状态之前更改其值:

const handleChange = (filter, label, value) => {
   const currentFilters = [...filterValues] // A new copy of the state.
   const newFilters = currentFilters.map(stateFilter => stateFilter[filter] ? {[filter]: [label, value]} : stateFilter)
   setFilterValues(newFilters);
 };

虽然我相信这可以解决您的情况,但我认为将过滤器存储在数组中会更好,这意味着对象结构为:

[[l1,v1], [l1, v2]]

这样,过滤器一就是过滤器阵列上的索引0,依此类推。因此,要做您想做的事情,您将拥有一个接收过滤器编号,标签和值的函数:

const handleChange = (filter, label, value) => {
   let newFilters = [...filterValues] // A new copy of the state.
   newFilters[filter - 1] = [label, value];
   setFilterValues(newFilters);
 };

请注意,如果收到的过滤器编号为1,表示第一个过滤器,则要访问过滤器数组上的位置0。

答案 1 :(得分:0)

const handleChange = (filter, label, value) => {
    filterValues.map(el => {
      for (let keys in el) {
        if (keys === filter) {
          el[filter] = [label, value];
          setFilterValues([el]);
        } else {
          let newObj = { [filter]: [label, value] };
          let finalArr = [...filterValues, newObj];
          setFilterValues(finalArr);
        }
      }
    });
  };

答案 2 :(得分:-1)

通过键在对象(即“地图”或“字典”)(而不是数组)中存储过滤器数组标签-值对,这使您可以通过键恒定时间(O(1))查找以更新的值按键进行过滤(复制并返回新的状态值是OFC仍为O(n))。

此外,使用功能状态更新来正确访问以前的状态并排队状态更新。

const [filterValues, setFilterValues] = useState({ f1: ["l","v"] });

const handleChange = (filter, label, value) => {
  setFilterValues(prevFilterValues => ({
    ...prevFilterValues,  // copy previous state
    [filter]: [label, value], // set the value for filter key
  }));
};

示例:

handleChange('f1', 'l1', 'v1');
// filterValues = { f1: ["l1", "v1"] }

handleChange('f2', 'l2', 'v2');
// filterValues = {
//   f1: ["l1", "v1"],
//   f2: ["l2", "v2"],
// }

handleChange('f1', 'l3', 'v3');
// filterValues = {
//   f1: ["l3", "v3"],
//   f2: ["l2", "v2"],
// }

演示:

//const [filterValues, setFilterValues] = useState({ f1: ["l","v"] });

// Manual mock for useState return values
let filterValues = { f1: ["l","v"] };
setFilterValues = stateUpdater => filterValues = stateUpdater(filterValues);

const handleChange = (filter, label, value) => {
  setFilterValues(prevFilterValues => ({
    ...prevFilterValues,  // copy previous state
    [filter]: [label, value], // set the value for filter key
  }));
};

// Start Demo
console.log('initial filterValues', filterValues); // { f1: ["l", "v"] }

handleChange('f1', 'l1', 'v1');
console.log('filterValues', filterValues); // { f1: ["l1", "v1"] }

handleChange('f2', 'l2', 'v2');
console.log('filterValues', filterValues); // { f1: ["l1", "v1"], f2: ["l2", "v2"] }

handleChange('f1', 'l3', 'v3');
console.log('filterValues', filterValues); // { f1: ["l3", "v3"], f2: ["l2", "v2"] }