"Right" 使用 React organize/manage 多模态的方法
"Right" way to organize/manage multiple modals with React
我正在自学 React,并且一直在构建一个简单的预算系统来完成它。我正在使用 React-Bootstrap 进行设计,并构建了一些不同的模式来处理我应用程序中的某些功能。
该应用程序运行良好,但作为一名开发人员,我觉得在我的代码设计方面可以收紧很多。
可以设计得更好的地方之一是我处理多重模态的方式。如您所见,我目前有 4 个模态框,所有模态框都被传递给各种道具(它们也被传递到 BudgetContainer 中)。其中一些功能(例如“setOpenModal”)是必需的,因为我需要能够控制从应用程序内的不同位置打开哪个模式。
然而,这种设计导致必须在我的应用程序中来回传递大量道具,以便让所有 data/functions 出现在我需要的地方。经过一些研究,我发现这就是所谓的 'prop-drilling'.
我已经研究了一些其他方法,例如某种全局状态管理方法(例如 Redux),但这些似乎都是非常笨拙的解决方案。
我还考虑过将模态框的位置移动到触发它们显示的同一组件上,但是我最终得到的是随机模态框分散在整个应用程序中,而不是在一个区域中。
我在这里忽略了一些设计模式吗?我只是一个 React 新手?我觉得模式在 Web 开发中是一个足够普遍的特性,因此必须已经存在解决方案。
import React, { useState } from 'react'
import { Row, Col } from 'react-bootstrap-v5'
import { useAsync } from 'react-async'
import budgetApi from '@/api/budgetApi.js'
import { transactionDefault } from '@/objectDefaults/transaction.js'
import BudgetContainer from './components/BudgetContainer.js'
import Cashflow from './components/Cashflow.js'
import UnbudgetedTransactions from './components/UnbudgetedTransactions.js'
import BudgetModal from '@/common/modals/BudgetModal'
import DeleteBudgetModal from '@/common/modals/DeleteBudgetModal'
import TransactionDetailModal from '@/common/modals/TransactionDetailModal'
import TransactionSplitModal from '@/common/modals/TransactionSplitModal'
function BudgetContent() {
const [activeBudget, setActiveBudget] = useState({})
const [activeTransaction, setActiveTransaction] = useState(transactionDefault)
const [activeDate, setActiveDate] = useState(new Date())
const [openModal, setOpenModal] = useState('')
// Retrieve the budgeting data
const { data, error, isPending, run } = useAsync({
promiseFn: budgetApi.getPromise,
deferFn: budgetApi.getDefer,
watch: activeDate,
onResolve: (resolvedData) => {
// Update the activeBudget's data
let freshActiveBudget = resolvedData.data.budgeted_transactions.filter(
freshBudget => freshBudget.id == activeBudget.id
)
setActiveBudget(freshActiveBudget[0] ?? {})
},
// PHP's Carbon library can easily parse ISO dates
period: activeDate.toISOString()
})
return (
<div>
<Row>
<Col md={7}>
<BudgetContainer
budgets={data && data.data.budgeted_transactions}
activeDate={activeDate}
setActiveDate={setActiveDate}
isPending={isPending}
activeBudget={activeBudget}
setActiveBudget={setActiveBudget}
setActiveTransaction={setActiveTransaction}
setOpenModal={setOpenModal}
/>
</Col>
<Col md={5}>
<Row>
<Col>
<Cashflow />
</Col>
</Row>
<Row className="pt-2">
<Col>
<UnbudgetedTransactions
transactions={data && data.data.unbudgeted_transactions}
setOpenModal={setOpenModal}
setActiveTransaction={setActiveTransaction}
/>
</Col>
</Row>
</Col>
</Row>
{<TransactionDetailModal
show={openModal == 'transaction_detail'}
setOpenModal={setOpenModal}
activeTransaction={activeTransaction}
refreshBudgets={run}
budgets={data && data.data.budgeted_transactions}
/>
<TransactionSplitModal
show={openModal == 'transaction_split'}
setOpenModal={setOpenModal}
activeTransaction={activeTransaction}
/>
<BudgetModal
show={openModal == 'create_budget'}
setOpenModal={setOpenModal}
refreshBudgets={run}
activeBudget={activeBudget}
/>
<DeleteBudgetModal
show={openModal == 'delete_budget'}
setOpenModal={setOpenModal}
refreshBudgets={run}
activeBudget={activeBudget}
setActiveBudget={setActiveBudget}
/>}
</div>
)
}
export default BudgetContent
最后我只是选择了使用React的ContextAPI来共享元素之间modals需要的信息,避免prop drilling
我正在自学 React,并且一直在构建一个简单的预算系统来完成它。我正在使用 React-Bootstrap 进行设计,并构建了一些不同的模式来处理我应用程序中的某些功能。
该应用程序运行良好,但作为一名开发人员,我觉得在我的代码设计方面可以收紧很多。
可以设计得更好的地方之一是我处理多重模态的方式。如您所见,我目前有 4 个模态框,所有模态框都被传递给各种道具(它们也被传递到 BudgetContainer 中)。其中一些功能(例如“setOpenModal”)是必需的,因为我需要能够控制从应用程序内的不同位置打开哪个模式。
然而,这种设计导致必须在我的应用程序中来回传递大量道具,以便让所有 data/functions 出现在我需要的地方。经过一些研究,我发现这就是所谓的 'prop-drilling'.
我已经研究了一些其他方法,例如某种全局状态管理方法(例如 Redux),但这些似乎都是非常笨拙的解决方案。
我还考虑过将模态框的位置移动到触发它们显示的同一组件上,但是我最终得到的是随机模态框分散在整个应用程序中,而不是在一个区域中。
我在这里忽略了一些设计模式吗?我只是一个 React 新手?我觉得模式在 Web 开发中是一个足够普遍的特性,因此必须已经存在解决方案。
import React, { useState } from 'react'
import { Row, Col } from 'react-bootstrap-v5'
import { useAsync } from 'react-async'
import budgetApi from '@/api/budgetApi.js'
import { transactionDefault } from '@/objectDefaults/transaction.js'
import BudgetContainer from './components/BudgetContainer.js'
import Cashflow from './components/Cashflow.js'
import UnbudgetedTransactions from './components/UnbudgetedTransactions.js'
import BudgetModal from '@/common/modals/BudgetModal'
import DeleteBudgetModal from '@/common/modals/DeleteBudgetModal'
import TransactionDetailModal from '@/common/modals/TransactionDetailModal'
import TransactionSplitModal from '@/common/modals/TransactionSplitModal'
function BudgetContent() {
const [activeBudget, setActiveBudget] = useState({})
const [activeTransaction, setActiveTransaction] = useState(transactionDefault)
const [activeDate, setActiveDate] = useState(new Date())
const [openModal, setOpenModal] = useState('')
// Retrieve the budgeting data
const { data, error, isPending, run } = useAsync({
promiseFn: budgetApi.getPromise,
deferFn: budgetApi.getDefer,
watch: activeDate,
onResolve: (resolvedData) => {
// Update the activeBudget's data
let freshActiveBudget = resolvedData.data.budgeted_transactions.filter(
freshBudget => freshBudget.id == activeBudget.id
)
setActiveBudget(freshActiveBudget[0] ?? {})
},
// PHP's Carbon library can easily parse ISO dates
period: activeDate.toISOString()
})
return (
<div>
<Row>
<Col md={7}>
<BudgetContainer
budgets={data && data.data.budgeted_transactions}
activeDate={activeDate}
setActiveDate={setActiveDate}
isPending={isPending}
activeBudget={activeBudget}
setActiveBudget={setActiveBudget}
setActiveTransaction={setActiveTransaction}
setOpenModal={setOpenModal}
/>
</Col>
<Col md={5}>
<Row>
<Col>
<Cashflow />
</Col>
</Row>
<Row className="pt-2">
<Col>
<UnbudgetedTransactions
transactions={data && data.data.unbudgeted_transactions}
setOpenModal={setOpenModal}
setActiveTransaction={setActiveTransaction}
/>
</Col>
</Row>
</Col>
</Row>
{<TransactionDetailModal
show={openModal == 'transaction_detail'}
setOpenModal={setOpenModal}
activeTransaction={activeTransaction}
refreshBudgets={run}
budgets={data && data.data.budgeted_transactions}
/>
<TransactionSplitModal
show={openModal == 'transaction_split'}
setOpenModal={setOpenModal}
activeTransaction={activeTransaction}
/>
<BudgetModal
show={openModal == 'create_budget'}
setOpenModal={setOpenModal}
refreshBudgets={run}
activeBudget={activeBudget}
/>
<DeleteBudgetModal
show={openModal == 'delete_budget'}
setOpenModal={setOpenModal}
refreshBudgets={run}
activeBudget={activeBudget}
setActiveBudget={setActiveBudget}
/>}
</div>
)
}
export default BudgetContent
最后我只是选择了使用React的ContextAPI来共享元素之间modals需要的信息,避免prop drilling