【问题标题】:What is the React Hooks way of handling multiple actions while also setting state?React Hooks 在设置状态的同时处理多个动作的方式是什么?
【发布时间】:2021-08-03 10:40:05
【问题描述】:

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

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

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

CatalogListCatalogPreview 组件接收上述状态值作为 props 以及它们的 setter 函数。

内部CatalogList.js

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

当你点击'探索'按钮时,它需要做4件事:

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

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

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

Link to Code Sandbox

问题:

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

【问题讨论】:

  • 这不一定是不正确的,尽管恕我直言,它可以改进。如果您可以更新您的问题以包含每个组件的完整 Minimal, Complete, and Reproducible Code Example,我想我可以更好地提出建议。
  • @DrewReese 添加了代码沙箱链接

标签: reactjs react-router react-hooks use-effect use-state


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

  2. 将持久化到 localStorage 移动到依赖于 catalog 状态的 useEffect 挂钩。当状态更新时,将其持久化到 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>
      );
    }
    

演示

【讨论】:

    猜你喜欢
    • 2019-11-18
    • 2023-03-26
    • 1970-01-01
    • 2019-07-21
    • 2020-11-13
    • 2020-11-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多