reactjs - useState 钩子(Hook)是否改变状态的值

标签 reactjs

我刚刚开始 React,在这个项目列表教程中我有一些关于更新项目状态的问题。另外,我在 app.js 中使用功能组件 .So

const [items, setItems] = useState([
  {
    id: 1,
    title: 'Banana',
    bought: false
  },
 ...
])

然后,我在 app.js 中有一个函数,可以在选中复选框时将购买更新为 true 或 false

// The id is passed in from Item.js down below
const markBought = (id) => {
  setItems(
    items.map(
     item => {
      if (item.id === id) {
        /// If bought is false, checking it will make it true and vice versa
        item.bought = !item.bought; // (1)
      }
      return item; // (2)
    })
  );
};
return (
  <div className="App">
    <Items items={items} markBought={markBought}></Items>
  </div>
);

老师说我们正在使用一种叫做组件钻探的东西。所以在Items.js中,我们对每一项进行映射,将其一一显示出来,但我认为没有必要显示。

最终在 Item.js 中

<input type="checkbox" onChange={() => props.markBought(props.item.id)} />
{props.item.title}

该应用程序运行良好,但对我来说有点困惑。所以:

  1. 在app.js中,当我们更改购买状态后,我们是否还需要返回商品,就像条件为假时返回商品一样?为什么只有在错误时才返回该项目,而在正确时我们只更改它而不返回?
  2. 我读到map不会修改数组,所以markBought函数应该创建一个新的items数组,并且已经购买了修改过的东西,但是这个数组会发生什么,React如何知道将其“props”到item.js,而不是我硬编码的?

抱歉,如果这有点长,我们将非常感谢您的帮助。感谢您的阅读

最佳答案

您正在改变 map 中的一个项目,如果您将 Item 组件优化为纯组件,那么该组件将不会因为突变而重新渲染。请尝试以下操作:

//use useCallback so marBought doesn't change and cause
//  needless DOM re renders
const markBought = useCallback(id => {
  setItems((
    items //pass callback to the setter from useState
  ) =>
    items.map(
      item =>
        item.id === id
          ? { ...item, bought: !item.bought } //copy item with changed value
          : item //not this item, just return the item
    )
  );
}, []);

这是一个完整的示例:

const { useCallback, useState, useRef, memo } = React;
function Items() {
  const [items, setItems] = useState([
    {
      id: 1,
      title: 'Banana',
      bought: false,
    },
    {
      id: 2,
      title: 'Peach',
      bought: false,
    },
  ]);
  const toggleBought = useCallback(id => {
    setItems((
      items //pass callback to the setter from useState
    ) =>
      items.map(
        item =>
          item.id === id
            ? { ...item, bought: !item.bought } //copy item with changed value
            : item //not this item, just return the item
      )
    );
  }, []);
  return (
    <div>
      {items.map(item => (
        <Item
          key={item.id}
          item={item}
          toggleBought={toggleBought}
        />
      ))}
    </div>
  );
}
//use memo to make Item a pure component
const Item = memo(function Item({ item, toggleBought }) {
  const renderedRef = useRef(0);
  renderedRef.current++;
  return (
    <div>
      <div>{item.title}</div>
      <div>bought: {item.bought ? 'yes' : 'no'}</div>
      <button onClick={() => toggleBought(item.id)}>
        toggle bought
      </button>
      <div>Rendered: {renderedRef.current} times</div>
    </div>
  );
});

//render the application
ReactDOM.render(<Items />, document.getElementById('root'));
<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="root"></div>

这是一个损坏的示例,其中您改变了项目,即使状态确实发生了变化,也看不到重新渲染:

const { useCallback, useState, useRef, memo } = React;
function Items() {
  const [items, setItems] = useState([
    {
      id: 1,
      title: 'Banana',
      bought: false,
    },
    {
      id: 2,
      title: 'Peach',
      bought: false,
    },
  ]);
  const toggleBought = useCallback(id => {
    setItems((
      items //pass callback to the setter from useState
    ) =>
      items.map(
        item =>
          item.id === id
            ? ((item.bought = !item.bought),item) //mutate item
            : item //not this item, just return the item
      )
    );
  }, []);
  return (
    <div>
      <div>
        {items.map(item => (
          <Item
            key={item.id}
            item={item}
            toggleBought={toggleBought}
          />
        ))}
      </div>
      <div>{JSON.stringify(items)}</div>
    </div>
  );
}
//use memo to make Item a pure component
const Item = memo(function Item({ item, toggleBought }) {
  const renderedRef = useRef(0);
  renderedRef.current++;
  return (
    <div>
      <div>{item.title}</div>
      <div>bought: {item.bought ? 'yes' : 'no'}</div>
      <button onClick={() => toggleBought(item.id)}>
        toggle bought
      </button>
      <div>Rendered: {renderedRef.current} times</div>
    </div>
  );
});

//render the application
ReactDOM.render(<Items />, document.getElementById('root'));
<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="root"></div>

关于reactjs - useState 钩子(Hook)是否改变状态的值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58893808/

相关文章:

javascript - redux 调度完成后的焦点输入

Javascript:-如何将值从表传递到 onClick 处理程序以实现删除功能

reactjs - 将光标更改为指针 google-maps-react

javascript - 选项卡打开时持续的 session 的身份验证逻辑

reactjs - 有些东西已经在端口 3000 上运行了

javascript - 如何修复 "Uncaught TypeError: Cannot read property ' value' of null”错误?

javascript - 如何将状态从子组件传递到应用程序组件

reactjs - 使用 typescript react 表出现问题

javascript - 绝对路径不适用于使用 typescript 创建 react 应用程序

reactjs - shuffle React 中的奇怪行为