[英]Using useEffect to move react query state to useState
So I have a table of salespeople that is populated using the map method.因此,我有一个使用 map 方法填充的销售人员表。 Each row in that table has an 'Edit' button that should 1) get the id of the row, 2) fetch the data for that record from the database using react query, and 3) open a modal and pass that the object data to the modal to populate the input fields.
该表中的每一行都有一个“编辑”按钮,该按钮应该 1) 获取行的 ID,2) 使用反应查询从数据库中获取该记录的数据,以及 3) 打开一个模式并将 object 数据传递给填充输入字段的模式。
At this point, I can do the above by passing the data to the modal directly using the react query response, but I want to put that response into a useState
variable to track my state locally for client operations (eg when adding a new salesperson, I need to pass an empty object into the modal instead of the last query result).在这一点上,我可以通过使用反应查询响应直接将数据传递给模态来执行上述操作,但我想将该响应放入
useState
变量中以在本地跟踪我的 state 以进行客户端操作(例如,添加新销售人员时,我需要将一个空的 object 传递给模态而不是最后一个查询结果)。
I'm pretty sure to do this, I need to incorporate useEffect
somehow, but I'm having trouble getting it to work properly.我很确定会这样做,我需要以某种方式合并
useEffect
,但我无法让它正常工作。 Would think it would be as easy as updating a usestate variable in the useeffect function, like so:会认为它就像在 useeffect function 中更新一个 usestate 变量一样简单,如下所示:
I tried doing something like this:我试着做这样的事情:
const [salespersonToModify, setSalespersonToModify] = React.useState({})
.....
React.useEffect(() => {
console.log(`effect salesperson:${idToEdit}`)
setSalespersonToModify(fetchedSalesperson)
}, [fetchedSalesperson])
.....
<ModifySalespersons
isOpen={isOpen}
setIsOpen={setIsOpen}
salesperson={salespersonToModify}
onSubmit={handleSubmit}
/>
But I'm not having any luck.但我没有任何运气。 Hoping someone can assist.
希望有人可以提供帮助。 Full code below
完整代码如下
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;
The algorithm can be like:该算法可以是这样的:
Practically, your editSalesPerson could be实际上,您的editSalesPerson可能是
import {useHistory} rom 'react-router-dom';
...
const history = useHistory()
const editSalesPerson = useCallback((personId) => {
history.push('/salespersons/' + personId);
}, [])
be sure that your comp Salespersons wrapped by:确保您的 comp Salespersons由以下人员包装:
<Route path="/salespersons/:id" component={Salespersons} />
all work out of Modal has done. Modal 的所有工作都已完成。 then you have to extract needed parameter from location.
那么你必须从位置中提取所需的参数。
inside your modal component(or just here) instead of your const [idToEdit, setIdToEdit] = React.useState(0)
在你的模态组件(或就在这里)而不是你的
const [idToEdit, setIdToEdit] = React.useState(0)
you already have an edit id which is您已经有一个编辑 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')
last part is to implement fetching inside your modal最后一部分是在你的模式中实现抓取
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])
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.