首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么useState提供的状态在某些特定情况下没有得到更新?

为什么useState提供的状态在某些特定情况下没有得到更新?
EN

Stack Overflow用户
提问于 2022-11-26 16:20:25
回答 2查看 41关注 0票数 0

我在StackOverflow上经历过许多类似的QnAs,但我仍然不明白为什么它对我不起作用。我知道状态更新是不同步的。而且,我不会执行任何DOM操作。

这里的完整演示演示了这个问题-- https://codesandbox.io/s/falling-pine-kljujf?file=/src/Tabs.js

在本例中,我呈现了几个选项卡。一个新的选项卡最初显示一个DB“表”名称的列表(这个示例是固定的)。在选择表名时,列表将被表的内容替换。

问题是当您关闭打开的选项卡时,currentTab状态不会更新到我要设置的(打开)选项卡。由于该选项卡的详细区域仍然是空白的,直到我手动单击打开的选项卡的名称。

在上面的图片中,我关闭了第三个选项卡。期望选项卡选择应该自动更改为第二个选项卡,但它没有。同样的代码如下所示。

代码语言:javascript
复制
  function removeTab(id) {
    const ntl = tabsList;
    const idx = ntl.findIndex((v) => v.id === id);
    if (idx !== -1) {
      ntl.splice(idx, 1);
      if (ntl.length) {
        let t = ntl[idx];
        console.log("------", t, idx);
        if (!t) {
          t = ntl[0];
        }
        console.log("++++++1", t, t.id);
        setCurrentTab(t.id);
        setTabsList([...ntl]);
      } else {
        const t = newTab();
        console.log("++++++2", t, t.id);
        setCurrentTab(t.id);
        setTabsList([t]);
      }
    }
  }

通过的id上方是第三个选项卡。tabsList状态包含一个数组,其中包含每个选项卡的数据。currentTab只包含当前选项卡的id。按照上面的console.log语句,将传递正确的选项卡的id,但是currentTab从不更新。即使我把代码写在下面。

代码语言:javascript
复制
useEffect(() => { console.log('------------>', currentTab) }, [currentTab]);

在这种情况下它从不开火。

removeTab方法是从JSX调用的,如下所示。

代码语言:javascript
复制
{tabsList.map((t) => (
          <a
            key={t.id + ""}
            className={
              "tab tab-bordered " + (currentTab === t.id ? "tab-active" : "")
            }
            onClick={() => {
              setCurrentTab(t.id);
            }}
          >
            {t.name}
            <button
              onClick={() => {
                removeTab(t.id); // On clicking X button we remove tab
              }}
            >
              X
            </button>
          </a>
        ))}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-11-26 16:49:10

有两个问题

  • 剪接是直接突变状态,为了防止这种情况,可以使用扩展操作符来制作数组的副本。
  • 2事实上,Button在Anchor标记中,并且都有onClick,所以当单击交叉按钮时,还会调用父锚点单击,为了防止这种情况,可以执行e.stopPropagation()。

这是我对代码框https://codesandbox.io/s/practical-platform-dvkxrq?file=/src/Tabs.js:3723-3738所做的编辑。

票数 1
EN

Stack Overflow用户

发布于 2022-11-26 17:46:46

我对代码做了一些修改,它们可能会帮助您找到更好的解决方案。

将初始值选项卡设置为状态,而不是useEffect、减少呈现周期

删除和添加创建一个新数组

你可以找到修改代码框示例

使用单个选定项呈现内容防止重复

唯一的问题是反应不是刷新删除上的更改,所以我不得不使用黑客,在这种情况下,您可能会发现这是有帮助的。

代码语言:javascript
复制
let tabId = 1;

const DisplayTable = ({ isNewMode, name, ...rest }) => {
  return (
    <div>
      {isNewMode ? (
        <TableSelection {...rest} />
      ) : (
        <div>Contents of table: {name}</div>
      )}
    </div>
  );
};

export default function Tabs() {
  const [tabsList, setTabsList] = useState([
    {
      id: tabId,
      name: "Select table",
      isNewMode: true
    }
  ]);
  const [currentTab, setCurrentTab] = useState(tabId);

  function newTab() {
    tabId = tabId + 1; // unique id check
    return {
      id: tabId,
      name: "Select table",
      isNewMode: true
    };
  }

  function addTab() {
    const t = newTab();
    setTabsList((tabs) => [...tabs, t]);
    console.log("++++++3", t, t.id);
    setCurrentTab(t.id);
  }

  async function removeTab(id) {

    //  functional updaters are simpler
    //  setTabsList(tabs => [...tabs.filter((a) => a.id !== id)])


    // need better logic to select the right tab, this seems simeple enough to understand
    const deleteIndex = tabsList.findIndex((v) => v.id === id);
    // 
    if (deleteIndex !== -1) {
      const filteredItems = tabsList.filter((a) => a.id !== id);

      if (deleteIndex > 0) {
        const prevId = filteredItems[deleteIndex - 1];
        console.log("prevId", prevId);

        setTabsList([...filteredItems]);
        await Promise.resolve();
        setCurrentTab(prevId.id);
      }
    }
  }

  const selectedItem = tabsList?.find((item) => item.id === currentTab);

  // console.log("Rendering......", currentTab, tabsList);
  return (
    <div className="p-8 h-full flex flex-col">
      <div className="tabs">
        {tabsList.map((t) => (
          <a
            href="#"
            key={t.id}
            className={
              "tab tab-bordered " + (currentTab === t.id ? "tab-active" : "")
            }
            onClick={(e) => {
              e.preventDefault();
              setCurrentTab(t.id);
            }}
          >
            {t.name}
            <button
              className="ml-2 btn btn-ghost btn-square btn-xs"
              onClick={(e) => {
                e.preventDefault();
                removeTab(t.id);
              }}
            >
              X
            </button>
          </a>
        ))}
        <a href="#" className="tab">
          <button
            className="btn btn-ghost btn-square btn-xs"
            onClick={(e) => {
              e.preventDefault();
              addTab();
            }}
          >
            +
          </button>
        </a>
      </div>
      {selectedItem ? (
        <DisplayTable
          onTableSelection={(item) => {
            tabId = tabId + 1;
            const d = { ...item, id: tabId, isNewMode: false };
            setTabsList((t) => [...t, d]);
            console.log("table select", d);
            setCurrentTab(d.id);
          }}
          {...selectedItem}
        />
      ) : null}
      {/* {tabsList.map((t) => (
        <div key={t.id}>
          <TableSelection />
        </div>
      ))} */}
    </div>
  );
}

希望在某种程度上是有用的,

干杯

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74583787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档