简体   繁体   English

使用 useEffect 将 react 查询 state 移动到 useState

[英]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:该算法可以是这样的:

  1. Render list of your entities(salesmen) what you have done.呈现您的实体(销售人员)您所做的事情的列表。
  2. Handle click on row and after this you need to store target person data:处理点击行,然后你需要存储目标人物数据:
  • put that data in useState将该数据置于 useState
  • if you need only id - you can push in to react-router. latest solution is better imho because of you can send the link with person details to somebody which may be way useful.如果你只需要id - 你可以推送到 react-router。最新的解决方案是更好的恕我直言,因为你可以将带有个人详细信息的链接发送给可能有用的人。
  1. need to teach your modal parse query parameter, use it in useEfect for fetching data, and put that data in useState of modal.需要教你的模态解析查询参数,在 useEfect 中使用它来获取数据,并将该数据放在模态的 useState 中。

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.

相关问题 React useState 和 useEffect 状态落后一步 - React useState and useEffect state is behind by one step 使用 React Hooks,使用“useState”和“useEffect”,有没有办法渲染一个状态直到状态有一个值? - Using React Hooks, using "useState" and "useEffect", is there a way to render a state waiting till the state has a value? 使用 react useState 和 useEffect 时的未知行为 - Unknown behavior when using react useState and useEffect React Hooks:在 useEffect 中使用 useState 不会在第一次渲染后立即设置状态 - React Hooks: using useState inside useEffect doesn't set the state immediately after first rendering 在 React 中使用 useState() 和 useEffect() 时设置来自 axios 的 state 值 - Setting state value coming from axios when using useState() and useEffect() in React 当 state 发生变化时做出反应,useState 和 useEffect 是否也更新了? - In react when state changes, are useState and useEffect also updated? React Hooks useState+useEffect+event 给出过时的状态 - React Hooks useState+useEffect+event gives stale state 在儿童的第一次渲染 useEffect 上用旧状态反应钩子 useState - React hook useState with old state on children's first render useEffect React useState &amp; useEffect 混淆 - React useState & useEffect confusion 使用 React 更新二维数组并挂钩 useState 和 useEffect - Update 2d array using React and hooks useState and useEffect
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM