所以我有一个使用map方法填充的销售人员表。该表中的每一行都有一个"编辑"按钮,该按钮应1(获取行的id,2(使用react查询从数据库中获取该记录的数据,以及3(打开一个模态并将对象数据传递给模态以填充输入字段。
在这一点上,我可以通过直接使用react查询响应将数据传递到模态来完成上述操作,但我想将该响应放入useState
变量中,以在本地跟踪我的状态以进行客户端操作(例如,当添加新的销售人员时,我需要将一个空对象传递到模态中,而不是最后一个查询结果(。
我很确定会这样做,我需要以某种方式合并useEffect
,但我很难让它正常工作。会认为这就像更新useeffect函数中的usestate变量一样容易,比如:
我试着做这样的事情:
const [salespersonToModify, setSalespersonToModify] = React.useState({})
.....
React.useEffect(() => {
console.log(`effect salesperson:${idToEdit}`)
setSalespersonToModify(fetchedSalesperson)
}, [fetchedSalesperson])
.....
<ModifySalespersons
isOpen={isOpen}
setIsOpen={setIsOpen}
salesperson={salespersonToModify}
onSubmit={handleSubmit}
/>
但我运气不好。希望有人能帮忙。以下的完整代码
import React, { useState, useEffect, useRef } from 'react';
import { useQuery, useMutation, useQueryCache, QueryCache, ReactQueryCacheProvider } from 'react-query'
import ModifySalespersons from '../components/ModifySalespersons'
function Salespersons(props){
const [page, setPage] = React.useState(1)
const [hasNextPage, setHasNextPage] = React.useState(true)
const [hasPreviousPage, setHasPreviousPage] = React.useState(false)
const [isOpen, setIsOpen] = React.useState(false)
const [idToEdit, setIdToEdit] = React.useState(0)
// api calls to abstract out
const fetchSalespersons = async (key, { page = 1 }) => {
const res = await fetch(`http://localhost:5000/api/salespersons?pagenumber=${page}&pagesize=4`);
let pagination = JSON.parse(res.headers.get("X-Pagination"));
setHasNextPage(pagination.hasNext);
setHasPreviousPage(pagination.hasPrevious);
return res.json();
}
const fetchSalesperson = async (key, salespersonId) => {
const res = await fetch(`http://localhost:5000/api/salespersons/${salespersonId}`);
return res.json();
}
const { data: salespersons, status: salespersonsStatus } = useQuery(['salespersons', { page } ], fetchSalespersons)
const { data: fetchedSalesperson, status: fetchedSalespersonStatus } = useQuery(['foundSalesperson', idToEdit], fetchSalesperson)
function addSalesPerson(){
// setFetchedSalesperson({});
setIsOpen(true);
}
function editSalesPerson(salespersonId){
fetchSalesperson(salespersonId)
.then((salesperson) => {
setIdToEdit(salespersonId)
setIsOpen(true);
});
}
React.useEffect(() => {
console.log(`effect salesperson:${idToEdit}`)
}, [idToEdit])
function handleSubmit(newSalesperson) {
console.log(newSalesperson);
// call api to create or update record
setIsOpen(false);
}
return (
<>
{fetchedSalespersonStatus === 'success' && (
<ModifySalespersons
isOpen={isOpen}
setIsOpen={setIsOpen}
salesperson={fetchedSalesperson}
onSubmit={handleSubmit}
/>
)}
{salespersonsStatus === 'loading' && (
<div class="fixed inset-0 transition-opacity flex items-center justify-center">
<div class="absolute inset-0 bg-gray-500 opacity-75"></div>
<button type="button" class="z-50 inline-flex items-center px-12 py-8 border border-transparent text-base leading-6 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition ease-in-out duration-150 cursor-not-allowed" disabled="">
<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
<p className="text-xl">
Loading
</p>
</button>
</div>
)}
{salespersonsStatus === 'error' && (
<div>
Error
</div>
)}
{salespersonsStatus === 'success' && (
<div onKeyDown={(event) => {if(event.key === "Escape") setIsOpen(false)}} tabIndex="0">
<div className="pb-5 border-b border-gray-200 space-y-3 sm:flex sm:items-center sm:justify-between sm:space-x-4 sm:space-y-0">
<h2 className="text-lg leading-6 font-medium text-gray-900">
Salespeople
</h2>
<div>
<span className="shadow-sm rounded-md">
<button onClick={ () => addSalesPerson() } type="button" className="inline-flex items-center px-4 py-2 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:shadow-outline-indigo focus:border-indigo-700 active:bg-indigo-700 transition duration-150 ease-in-out">
Add new salesperson
</button>
</span>
</div>
</div>
<div className="flex flex-col">
<div className="-my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="py-2 align-middle inline-block min-w-full sm:px-6 lg:px-8">
<div className="shadow overflow-hidden border-b border-gray-200 sm:rounded-lg">
<table className="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<th className="px-6 py-3 bg-gray-50 text-left text-xs leading-4 font-medium text-gray-500 uppercase tracking-wider">
Id
</th>
<th className="px-6 py-3 bg-gray-50"></th>
</tr>
</thead>
<tbody className="bg-white divide-y divide-gray-200">
{ salespersons.map((salesperson, index) => (
<tr>
<td className="px-6 py-4 whitespace-no-wrap text-sm leading-5 text-gray-500">
{salesperson.salespersonId}
</td>
<td className="px-6 py-4 whitespace-no-wrap text-right text-sm leading-5 font-medium">
<button onClick={ () => editSalesPerson(salesperson.salespersonId) } className="text-indigo-600 hover:text-indigo-900">Edit</button>
</td>
</tr>
))}
</tbody>
</table>
<nav className="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6">
<div className="flex-1 flex justify-between sm:justify-end">
<PageButtons page={page} setPage={setPage} hasPreviousPage={hasPreviousPage} hasNextPage={hasNextPage}></PageButtons>
</div>
</nav>
</div>
</div>
</div>
</div>
</div>
)}
</>
);
}
function PageButtons(props) {
return (
<>
{ props.hasPreviousPage && (
<button onClick={ () => props.setPage(props.page - 1) } className="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Previous
</button>
)}
{ props.hasNextPage && (
<button onClick={ () => props.setPage(props.page + 1) } className="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm leading-5 font-medium rounded-md text-gray-700 bg-white hover:text-gray-500 focus:outline-none focus:shadow-outline-blue focus:border-blue-300 active:bg-gray-100 active:text-gray-700 transition ease-in-out duration-150">
Next
</button>
)}
</>
);
}
export default Salespersons;
算法可以是:
- 呈现您所做的实体(销售人员(的列表
- 处理点击行,然后您需要存储目标人员数据:
- 将该数据置于useState
- 如果你只需要id-你可以推到react路由器。最新的解决方案是更好的imho,因为你可以将带有个人详细信息的链接发送给某人,这可能非常有用
- 需要教授模态解析查询参数,在useEfect中使用它来获取数据,并将该数据置于模态的useState中
实际上,您的editSalesPerson可能是
import {useHistory} rom 'react-router-dom';
...
const history = useHistory()
const editSalesPerson = useCallback((personId) => {
history.push('/salespersons/' + personId);
}, [])
请确保您的公司销售人员由包装
<Route path="/salespersons/:id" component={Salespersons} />
莫代尔的所有工作都完成了。然后您必须从位置提取所需的参数。
在模态组件内部(或仅在此处(,而不是const [idToEdit, setIdToEdit] = React.useState(0)
你已经有一个编辑id,它是
const params = useParams(); // params.id : undefined | string
Also you do not need to use this
*const [isOpen, setIsOpen] = React.useState(false)*
because of isOpen now is
*const isOpen = params && params.id;*
and dialog would be closed by execution:
history.push('salespersons')
最后一部分是在您的模式中实现提取
const [data, setData] = useState()
const [loading, setLoading] = useState(false)
useEffect(() => {
if (isOpen) {
;(async function() {
setLoading(true)
try {
const response = await api.etchSalesmanById(params.id);
setData(response.data); // or whatever, depends on how you set your API up.
} catch (e) {
console.log(e)
} finally {
setLoading(false)
}
})()
}
}, [isOpen])