【问题标题】:How to re-render react component when mapping over state that is array of objects映射对象数组的状态时如何重新渲染反应组件
【发布时间】:2019-09-29 01:48:48
【问题描述】:

我正在尝试映射处于状态的对象数组,有条件地从该状态返回两个反应组件之一。然后我会在某个时候更改该状态,并希望组件在其对象状态更改时重新渲染。我知道我的问题与 React 无法识别差异中的变化有关,但我不确定为什么以及需要更改什么模式才能使其正常工作。

这是一个代码笔: https://codepen.io/steven-harlow/pen/KKPLXRO

以及其中的代码:

const App = (props) => {
  const [todos, setTodos] = React.useState([
    {name: 'A', done: false},
    {name: 'B', done: false},
    {name: 'C', done: false},
  ])

  React.useEffect(() => {

  }, [todos])

  const handleClick = (name) => {
    const index = todos.find(todo => todo.name == name)
    let tempTodos = todos;
    tempTodos[index].done = true;
    setTodos(tempTodos);
  }

  return (
    <div>
      <h1>Hello, world!</h1>
      <div>
        {todos.map(todo => {
          return todo.done ? (<div key={'done' + todo.name}>{todo.name} : done</div>) : (<div onClick={() => handleClick(todo.name)} key={'notdone' + todo.name}>{todo.name} : not done</div>)
        })}
      </div>
    </div>
  )
}

【问题讨论】:

  • 在此处查看更新的 codepen codepen.io/marudhupandiyang/pen/WNeBZYB
  • 如果你需要索引你应该使用findIndex而不是find。如果您需要查找,我发送的灵魂将起作用。
  • 感谢@Panther。我的实际代码使用了 findIndex,但我快速通过并错过了那个 codepen。看起来我的错误是我假设我正在创建一个新数组(我已经阅读过它是需要的),而我只是引用了旧数组。

标签: reactjs react-hooks


【解决方案1】:

给你,这里现在应该适合你。我在那里添加了一些注释。

const App = (props) => {
  const [todos, setTodos] = React.useState([
    {name: 'A', done: false},
    {name: 'B', done: false},
    {name: 'C', done: false},
  ])

  const handleClick = (name) => {
    /*
      Here you were using todos.find which was returning the object. I switched
      over to todos.findIndex to give you the index in the todos array. 
    */
    const index = todos.findIndex(todo => todo.name === name)
    /*
      In your code you are just setting tempTodos equal to todos. This isn't
      making a copy of the original array but rather a reference. In order to create 
      a copy I am adding the .slice() at the end. This will create a copy.
      This one used to get me all of the time.
    */
    let tempTodos = todos.slice();
    tempTodos[index].done = true;
    setTodos(tempTodos);
  }
  console.log(todos)
  return (
    <div>
      <h1>Hello, world!</h1>
      <div>
        {todos.map((todo,index) => {
        return todo.done ? (<div key={index}>{todo.name} : done</div>) : (<div onClick={() => handleClick(todo.name)} key={index}>{todo.name} : not done</div>)
        })}
      </div>
    </div>
  )
}


ReactDOM.render(
  <App />,
  document.getElementById('root')
);

我做的另一件事是简化地图创建的 div 的键。我只是将索引添加到地图并将其用作键,这样更干净。

希望这会有所帮助!

【讨论】:

  • 啊,我的问题是我假设我正在创建一个新数组,但只是引用了原始数组。那固定的东西。我的原始代码使用了 findIndex,但在 codepen 中我忽略了它。
  • 这是一篇关于该主题的有用文章。 samanthaming.com/tidbits/35-es6-way-to-clone-an-array
  • 我完全忘了用切片创建副本,所以谢谢你这么清楚地提到!
【解决方案2】:

除非您创建一个新数组,否则 React 不会将状态视为 已更改

const handleClick = n => setTodos(todos.map(t => t.name === n ? {...t, done: true} : t));

【讨论】:

    猜你喜欢
    • 2022-07-12
    • 2019-04-03
    • 2018-04-04
    • 1970-01-01
    • 1970-01-01
    • 2022-07-08
    • 2021-01-27
    • 2021-10-15
    • 1970-01-01
    相关资源
    最近更新 更多