3

所以我有一张使用 map 方法填充的销售人员表。该表中的每一行都有一个“编辑”按钮,应该 1) 获取行的 id,2) 使用反应查询从数据库中获取该记录的数据,以及 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;

4

1 回答 1

0

该算法可以是:

  1. 呈现您所做的实体(销售人员)列表。
  2. 处理单击行,之后您需要存储目标人员数据:
  • 将该数据置于 useState
  • 如果你只需要id - 你可以推入 react-router。最新的解决方案更好恕我直言,因为您可以将包含个人详细信息的链接发送给可能有用的人。
  1. 需要教您的模态解析查询参数,在 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])

于 2020-10-08T13:42:43.190 回答