根据React中的键更新状态

时间:2019-02-15 15:51:53

标签: javascript reactjs ecmascript-6

我有状态结构,一开始就是这样:

messages:[
        {id: 1, name: 'name1'},
        {id: 2, name: 'name2'}, ...
    ]

我想要的是根据其id键更新一条消息。我正在从服务器获取另一个这样的对象:

{id: 2, name: 'newName2'}

状态是一个数组:(2) [{…}, {…}]。我不知道哪个索引的元素将被更新,我只知道对象内部的id键。

如何根据状态的键值更新状态内的对象?

6 个答案:

答案 0 :(得分:2)

您可以使用findIndex来获取要更新的对象的索引,并将其替换为新数组中的新对象,并将其设置为组件状态。

示例

class App extends React.Component {
  state = {
    messages: [{ id: 1, name: "name1" }, { id: 2, name: "name2" }]
  };

  updateMessage(newMessage) {
    this.setState(prevState => {
      const messages = [...prevState.messages];
      const index = messages.findIndex(m => m.id === newMessage.id);

      messages[index] = newMessage;

      return { messages };
    });
  }

  render() {
    return (
      <div>
        {this.state.messages.map(message => (
          <div key={message.id}>{message.name}</div>
        ))}
        <button onClick={() => this.updateMessage({ id: 2, name: "newName2" })}>
          Update message
        </button>
      </div>
    );
  }
}

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

<div id="root"></div>

答案 1 :(得分:2)

如果需要通过键查找它们,最好将它们存储为{key:'value'}对。

您有一些选择。

  • 如果您的密钥是ID,并且与索引匹配,则可以直接访问它。
  • 环绕数组
  • 使用[].find
  • 将列表转换为对象并查找。
  • 使用map
  • findIndex
  • .. etc

let id = 1
let message = messages [id -1];
message.foo = 'bar';

let prop = 'name', key = 'name1'
for (const message of messages) if (message[prop] === key) message.foo = 'bar'

const byProp = (prop,key) => ({[prop]:k}) => k == key
const message = messages.find (byProp('name', 'name1'))

const byProp = (arr,prop) => arr.reduce ((obj, itm) => ({...obj, [itm[prop]]:itm}),{})
let message = byProp (messages, 'name')['name1']

答案 2 :(得分:1)

这应该有效

 const newMsg = { id: 10, message: 'hi' }

 this.setState(({ messages } => {
    return {
       ...messages.filter(x => x.id !== newMsg.id),
       newMsg
    }
 };

答案 3 :(得分:1)

使用Array.map修改数组

const messages = [
    {id: 1, name: 'name1'},
    {id: 2, name: 'name2'},
]

const updateById = obj => {
  const { id } = obj;
  // here we check if new object has the same id as the old one
  // we replace old one with new
  return messages.map(message => message.id === id ? obj : message)
}

console.log(
  updateById({id: 1, name: 'newName'})
)

答案 4 :(得分:1)

有很多方法可以做到这一点。其中之一如下所示。

let x = [{id: 1, a: 1},{id: 2, b: 2}]

let newO = {id: 2, b: 3}

let y =[
    ...x.map(item => {
        if (item.id === newO.id) {
            return newO;
        } else return item
    })
]

console.log(y)

答案 5 :(得分:1)

这里是codesandbox,显示了下面的代码。

假设您像这样存储state

    state = {
       messages: [
         { id: 1, name: 'name1' },
         { id: 2, name: 'name2' },
         { id: 3, name: 'name3' }
      ]
    }

然后,您可以使用findIndex()根据ID查找消息,但是您还想确保不可变地更新状态。因此,您可以执行以下操作:

  changeMessage = (id, newName) => {

    // Search messages for a message with the given id, and return index
    // of the matching message in array, or -1 if not found.
    const arrayIndex = this.state.messages.findIndex((message) => (message.id === id))

    if (arrayIndex === -1) {
      console.log('No message found for id ' + id)
      return
    }

    // Copy over the messages from state to an array that
    // you can manipulate without affecting this.state.messages
    let updatedMessages = [...this.state.messages]

    // Update the message located by index
    updatedMessages[arrayIndex] = {
      id,
      name: newName
    }
    this.setState({
      messages: updatedMessages
    })
  }
}