首页 > 解决方案 > React Hooks 在设置状态的同时处理多个动作的方式是什么?

问题描述

我有 4 个组件:App, CatalogList, CatalogPreview, CatalogDetail

App是父组件,我有这些状态值:

const [catalog, setCatalog] = useState({ id: 1, name: 'Electronics' })
const [isModalOpen, setIsModalOpen] = useState(false)

CatalogListCatalogPreview组件接收上述状态值作为道具以及它们的设置器函数。

内部CatalogList.js

我有一个目录链接列表(电子产品、家具……),当您单击其中一个时,
它会打开CatalogPreview模式。在模态框内,有一个“探索”按钮。

当您单击“探索”按钮时,它需要做 4 件事:

将所选目录设置为状态(在 App.js 中)
将所选目录保存在 localStorage
导航到详细信息页面
关闭模式窗口

我在“探索”按钮的点击处理程序中尝试了以下操作(在模式内):

function explore() {
  props.setCatalog({...})
  props.setIsModalOpen(false)
  window.localStorage.setItem('catalog', JSON.stringify({...})
  history.push('detail-route') // this brings up the CatalogDetail
}

链接到代码沙箱

问题:

  1. 这是正确的方法吗?
  2. CatalogDetail组件中,如果我单击删除按钮并发出删除 API 请求,那么在调用完成
    如何导航回CatalogList路由。

标签: reactjsreact-routerreact-hooksuse-effectuse-state

解决方案


  1. 与其将模态打开/关闭状态存储在父App组件中,不如将其降级CatalogList为管理模态的子组件。

  2. 将持久化到 localStorage 移动到useEffect依赖于catalog状态的钩子。当状态更新时,将其持久化到 localStorage。

  3. 创建一个updateCatalog回调函数来接受一个新值来更新目录状态。将此传递给CatalogList.

  4. 回调应该被explore提升/提升到CatalogList组件。这允许CatalogPreview基本上只渲染模态。explore仍然调用更新目录数据、关闭模式和导航。

    应用程序

    function App() {
      const [catalog, setCatalog] = useState({ id: 1, name: "Electronics" });
    
      useEffect(() => {
        window.localStorage.setItem("catalog", JSON.stringify(catalog));
      }, [catalog]);
    
      const updateCatalog = value => {
        setCatalog( ...value... );
      };
    
      return (
        <Switch>
          <Route exact path="/">
            <CatalogList updateCatalog={updateCatalog} />
          </Route>
          <Route exact path="/detail">
            <CatalogDetail catalog={catalog} />
          </Route>
        </Switch>
      );
    }
    

    目录列表

    function CatalogList(props) {
      const history = useHistory();
    
      const [isOpen, setIsOpen] = useState(false);
      const catalogs = [
        { id: 1, name: "Electronics" },
        { id: 2, name: "Furniture & Appliances" },
        { id: 3, name: "Sports & Outdoors" }
      ];
    
      const openPreview = () => {
        setIsOpen(true);
      };
    
      function explore() {
        props.updateCatalog(... some new value ...);
        setIsOpen(false);
        history.push("/detail");
      }
    
      return (
        <div>
          Available catalogs
          <ul>
            {catalogs.map((c, index) => (
              <li key={c.id} onClick={() => openPreview(c.id)} className="link">
                {c.name}
              </li>
            ))}
          </ul>
          <CatalogPreview isOpen={isOpen} onExplore={explore} />
        </div>
      );
    }
    

    目录预览

    function CatalogPreview(props) {
      return (
        <Modal show={props.isOpen}>
          <Modal.Header closeButton>
            <Modal.Title>Catalog Preview</Modal.Title>
          </Modal.Header>
          <Modal.Footer>
            <Button variant="primary" onClick={props.onExplore}>
              Explore
            </Button>
          </Modal.Footer>
        </Modal>
      );
    }
    
  5. 使用useHistory并更新onClick处理程序以导航回主页。

    function CatalogDetail(props) {
      const history = useHistory();
    
      return (
        <div>
          <p>Detail Page</p>
          <button
            onClick={() => {
              // Make API call then navigate home
              history.push("/");
            }}
          >
            DELETE
          </button>
        </div>
      );
    }
    

演示

编辑what-is-the-react-hooks-way-of-handling-multiple-actions-while-also-setting-stat


推荐阅读