如何在不创建新obj的情况下连接到数组对象?

时间:2020-06-04 20:21:35

标签: javascript reactjs

如何在新对象Time上添加新key: 1的持续更新状态?

这是它的外观:

time: ["21:10:56", "21:10:56", "21:10:56"]

当前,每次我按一个键都会创建一个新对象。

enter image description here

当我在Number Two输入中输入值以拥有自己的key: 2对象并向其添加时间值时,情况也是如此。

const {useState, useEffect} = React;

const App = () => {
  const [state, setState] = useState([])

  const handleChange = (e, key) => {
    const d = new Date()
    const time = `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`

    setState((prevState) => {
      // console.log(state[0].time)
      // const initialArray = state.concat({ time })
      // console.log('test', initialArray)
      // const newArray = [...initialArray, { time }]

      return [...prevState, { key, time: [time] }]
      // return prevState.concat({ key, time: [time] })
    })
  }
  
    useEffect(() => {
    console.log(state)
  }, [state])
  
  return (
    <div>
      <div>
        <p>
          {`Number One:`}
          <input type="number" onChange={(e) => handleChange(e, 1)} />
        </p>
      </div>

      <div>
        <p>
          {`Number Two:`}
          <input type="number" onChange={(e) => handleChange(e, 2)} />
        </p>
      </div>
    </div>
  );
};

ReactDOM.render(
  <App/>,
  document.getElementById("react")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="react"></div>

3 个答案:

答案 0 :(得分:2)

您正在通过执行return [...prevState, { key, time: [time] }]向prevState添加新项目。取而代之的是,您需要找到与被调用的句柄更改具有相同键的项,并将时间推送到时间数组,或者如果找不到该项,则创建一个新对象。

 const handleChange = (e, key) => {
  const d = new Date()
  const time = `${d.getHours()}:${d.getMinutes()}:${d.getSeconds()}`

  setState((prevState) => {
    let object = prevState.find(obj => obj.key === key);
    if (!object) {
      prevState.push({key, time: [time]});
    }  
    else object.time.push(time)

    return prevState;
  })
}

答案 1 :(得分:2)

我将使用key作为属性名称和time作为值将状态更改为对象,然后使用类似JakeParis' answer的对象。

但是,如果那是您所坚持的:

setState((prevState) => {
  return [...(prevState?.filter(el => el.key !== key) || []), {
    key,
    time: [...(prevState?.find(el => el.key === key)?.time || []), time]
  }];
})

这将返回一个新数组,该数组具有(第一次扩展)键处于不同状态的先前状态中的所有元素,然后返回具有您正在使用的键的对象的新副本,且时间值设置为具有该键的元素的时间数组的先前值的数组(如果为新键,则为空数组),以及传递的时间。

以上内容适用于browsers supporting optional chaining,其中的数目令人惊讶。这是适用于旧版浏览器的一种:

setState((prevState) => {
  return prevState ? [...prevState.filter(el => el.key !== key), {
    key,
    time: [...(prevState.find(el => el.key === key) ? prevState.find(el => el.key === key).time : []), time]
  }] : [{key, time: [time] }];
})

答案 2 :(得分:1)

我相信您的错误在这里:

return [...prevState, { key, time: [time] }]

应该是:

const newTimeArray = [...prevState[key].time];
newTimeArray.push(time);
return { ...prevState, key: newTimeArray };

更新

HereticMonkey指出state是一个数组而不是对象,因此应该返回一个数组。但是总体思路仍然成立。