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