【问题标题】:Managing Button State and Resultant Processing with React Hooks使用 React Hooks 管理按钮状态和结果处理
【发布时间】:2020-04-30 13:39:58
【问题描述】:

我有一些可以打开/关闭的开关。它们从父功能组件获得开/关状态。当用户切换状态时,我需要更新父级中的状态并运行一个函数。

该函数使用所有切换的状态来过滤状态中的项目列表,然后更改图形可视化组件中呈现的绘图。

目前,它们切换得很好,但是渲染与按钮的状态不同步,因为处理函数最终以旧状态读取。

我尝试使用 useEffect(),但由于该函数有很多依赖项,因此会导致循环。

我尝试在自定义挂钩中将 useRef() 与 useState() 结合起来,以读出至少设置的最新过滤器组的当前状态,但那里也没有运气。

关于如何以更好的方式重新构建我的代码,或对当前问题的潜在解决方案有什么建议?

进行过滤的总函数:

function filterItems(threshold, items = {}) {
    const { values } = kCoreResult;
    const { coloredItems } = rgRef.current;

    let itemsForUse;
    let filteredItems;

    if (Object.entries(items).length === 0 && items.constructor === Object) {
      itemsForUse = baseItemsRef.current;
    } else {
      itemsForUse = items;
    }

    const isWithinThreshold = id => has(values, id) && values[id] >= threshold;

    // filter for nodes meeting the kCoreValue criterion plus all links
    filteredItems = pickBy(
      itemsForUse,
      (item, id) => !isNode(item) || isWithinThreshold(id)
    );
    filteredItems = pickBy(
      filteredItems,
      item =>
        !has(item, 'data.icon_type') || !filterRef.current[item.data.icon_type]
    );

    setRg(rg => {
      rg.filteredItems = leftMerge(filteredItems, coloredItems);

      return {
        ...rg,
      };
    });

    setMenuData(menuData => {
      menuData.threshold = threshold;

      return {
        ...menuData,
      };
    });
  }

在按下按钮后调用它的函数也更新按钮状态(按钮状态从过滤器对象向下传递):

function changeCheckBox(id, checked) {
    setFilter(filter => {
      filter[id] = !checked;

      return {
        ...filter,
      };
    });

    filterItems(menuData.threshold);
  }

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    似乎调用你的 filterItems 函数 in 处理程序正在导致陈旧状态错误,状态更新尚未协调。分离出更新状态的函数并“侦听”更新状态以运行过滤器功能。

    这是一个有助于了解模式的演示:

    export default function App() {
      const [filters, setFilters] = useState(filterOptions);
    
      const onChangeHandler = e => {
        setFilters({ ...filters, [e.target.name]: e.target.checked });
      };
    
      const filterItems = (threshold, items = {}) => {
        console.log("Gross function that does the filtering");
        console.log("threshold", threshold);
        console.log("items", items);
      };
    
      useEffect(() => {
        filterItems(42, filters);
      }, [filters]);
    
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
    
          {Object.entries(filters).map(([filter, checked]) => {
            return (
              <Fragment key={filter}>
                <label htmlFor={filter}>{filter}</label>
                <input
                  id={filter}
                  name={filter}
                  type="checkbox"
                  checked={checked}
                  onChange={onChangeHandler}
                />
              </Fragment>
            );
          })}
        </div>
      );
    }
    

    这是通过将状态更新与状态副作用解耦来实现的。处理程序通过始终返回具有下一个过滤器值的新对象来更新过滤器状态,并且效果挂钩会在值更改为 filters 时触发。

    【讨论】:

    • 嘿,这很有意义,非常感谢您的帮助。在此示例中,如果阈值也是一种状态,例如:codesandbox.io/s/… 我将如何补救“React Hook useEffect 缺少依赖项:'filterItems'。要么包含它,要么删除依赖项数组。(react-hooks/详尽的deps)”问题?就好像我确实在依赖数组中添加了阈值一样,当它发生变化时,我的应用程序将在不应该运行这个函数时运行。
    • threshold 更新了我的沙箱。
    • 啊,是的,所以在更新后的沙箱中,当我们设置新阈值时,“进行过滤的总函数”再次运行,我相信这是我正在寻找的最后一块拼图解决。我想找到一个选项,可以实现相同的效果,但该函数仅在过滤器更改时运行,而不是函数中的阈值等其他状态。
    • 能分享一下什么情况下应该调用filter函数吗?
    • 当然,所以在这个例子中,如果有办法让函数只在过滤器改变时运行,即使它使用阈值状态,那将完全解决我的问题。
    猜你喜欢
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-06
    • 2020-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多