reactjs - React Hooks 在设置状态的同时处理多个动作的方式是什么?
问题描述
我有 4 个组件:App, CatalogList, CatalogPreview, CatalogDetail
App
是父组件,我有这些状态值:
const [catalog, setCatalog] = useState({ id: 1, name: 'Electronics' })
const [isModalOpen, setIsModalOpen] = useState(false)
CatalogList
和CatalogPreview
组件接收上述状态值作为道具以及它们的设置器函数。
内部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
}
问题:
- 这是正确的方法吗?
- 在
CatalogDetail
组件中,如果我单击删除按钮并发出删除 API 请求,那么在调用完成后
如何导航回CatalogList
路由。
解决方案
与其将模态打开/关闭状态存储在父
App
组件中,不如将其降级CatalogList
为管理模态的子组件。将持久化到 localStorage 移动到
useEffect
依赖于catalog
状态的钩子。当状态更新时,将其持久化到 localStorage。创建一个
updateCatalog
回调函数来接受一个新值来更新目录状态。将此传递给CatalogList
.回调应该被
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> ); }
使用
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> ); }
演示
推荐阅读
- angular - 我无法理解语法:(
组件引用实例) - php - Codeigniter 加入命中
- angular - 为什么 .map 运算符在没有 .pipe (Angular + Angularfire2/auth) 的情况下无法工作?
- math.net - 拟合多项式显示函数
- json - 如何在 React Js 中使用我的 api 进行登录验证
- compiler-errors - 我收到使用 Cmake 的编译错误;编译器使用-clang;错误:使用未声明的标识符“sscanf_l”
- java - 如何从传递给函数的列表 T[] 中获取泛型 T 的类型,然后使用 T 进行实例化?
- javascript - 将值从后端代码传递到 Javascript 时的变量命名
- android - 在不使用root的情况下禁用android充电
- ibm-mq - MQPUT 成功但消息在远程队列中不可用