React:切换状态时,输入值未在多个字段中正确更新

问题描述 投票:0回答:1

我有一个 React 组件,其中多个玩家的输入值应该独立更新。当我切换状态时,第一个输入的值错误地传播到所有其他输入。此外,清除值会在某些输入中留下残留值。我需要帮助解决此同步问题。

这是我当前的代码实现,但问题是当我更改第一个输入的值(如果它有 4 个字母)时,比如说,当我从第一个输入中删除所有字母时,我在所有其他输入中也得到 3 个字母 在所有其他中,始终保留一个数字或字母并不会删除所有


  const getFilteredData = (
    data: IPlayerTestsResponse[],
    categoryId: string
  ) => {
    if (!categoryId) return null;
    return data.find((data) => data.player_test_id === categoryId);
  };

  const getTestResults = (
    data: IPlayerTestsResponse[],
    categoryId: string,
    mode: 'edit' | 'add'
  ) => {
    const result: {
      [userId: string]: { target: string; result: string };
    } = {};

    if (mode === 'edit' && categoryId) {
      const filteredData = getFilteredData(data, categoryId);
      if (!filteredData) return result;
      filteredData.results.forEach(
        (resultData) =>
          (result[resultData.user_id] = {
            target: resultData.target.toString(),
            result: resultData.result.toString()
          })
      );
    } else {
      players.forEach((player) => {
        result[player.user_id] = {
          target: '',
          result: ''
        };
      });
    }
    return result;
  };

  const [testResults, setTestResults] = useState<{
    [userId: string]: {
      target: string;
      result: string;
    };
  }>(getTestResults(testResultsData, dropdownInputValue, mode));

 useEffect(() => {
    if (dropdownInputValue) {
      const updatedTestResults = getTestResults(
        testResultsData,
        dropdownInputValue,
        mode
      );
      setTestResults(updatedTestResults);
    } else {
      const resetResults = getTestResults(testResultsData, '', 'add');
      setTestResults(resetResults);
    }
  }, [dropdownInputValue, mode, testResultsData]);


  const handleTestResultChange = (
    userId: string,
    type: 'target' | 'result',
    value: string
  ) => {
    setTestResults((prevResults) => {
      const updatedResults = { ...prevResults };

      if (type === 'target' && target) {
        const keys = Object.keys(prevResults);
        const firstTargetValue = keys.length ? prevResults[keys[0]].target : '';
        keys.forEach((key) => {
          updatedResults[key] = {
            ...updatedResults[key],
            target: key === userId ? value : firstTargetValue
          };
        });
      } else {
        updatedResults[userId] = {
          ...updatedResults[userId],
          [type]: value
        };
      }

      return updatedResults;
    });
  };

  const handleTargetChange = () => {
    setTarget((prevTarget) => {
      const newTarget = !prevTarget;

      setTestResults((prevResults) => {
        const updatedResults = { ...prevResults };

        if (newTarget) {
          const keys = Object.keys(prevResults);
          const firstTargetValue = keys.length
            ? prevResults[keys[0]].target
            : '';

          keys.forEach((userId) => {
            updatedResults[userId] = {
              ...updatedResults[userId],
              target: firstTargetValue
            };
          });
        } else {
          Object.keys(prevResults).forEach((userId) => {
            updatedResults[userId] = {
              ...updatedResults[userId],
              target: ''
            };
          });
        }

        return updatedResults;
      });

      return newTarget;
    });
  };

import TestResultTableRow from '../TestResultTableRow/TestResultTableRow';

import './TestResultTable.scss';

type Props = {
  players: IPlayer[];
  target: boolean;
  handleTestResultChange: (
    userId: string,
    type: 'target' | 'result',
    value: string
  ) => void;
  testResults: {
    [userId: string]: {
      target: string;
      result: string;
    };
  };
};

export default function TestResultTable({
  target,
  handleTestResultChange,
  testResults,
  players
}: Props) {
  // console.log('Players', players);

  // console.log('testResults BEFORE MAP', testResults);

  let counter = 0;

  return (
    <div className="test-result-table">
      <>
        <TestResultTableRow gridColumns={3}>
          <div className="test-result-table__name">PLAYER</div>
          <div className="test-result-table__target">TARGET</div>
          <div className="test-result-table__target">RESULT</div>
        </TestResultTableRow>
      </>
      <div className="test-result-table__body">
        {players.map((player, index) => {
          counter++;
          console.log(index, counter);
          return (
            <TestResultTableRow key={player.user_id} gridColumns={3}>
              <div className="test-result-table__body__name">{`${player.firstname} ${player.lastname}`}</div>

              <input
                className={`test-result-table__body__target ${target && index !== 0 ? ' test-result-table__body__target--filled' : ''}`}
                name="target[]"
                type="text"
                value={testResults[player.user_id]?.target || ''}
                onChange={(e) =>
                  handleTestResultChange(
                    player.user_id,
                    'target',
                    e.target.value
                  )
                }
                disabled={target && index !== 0}
              />

            
              <input
                className="test-result-table__body__target "
                type="text"
                value={testResults[player.user_id]?.result || ''}
                onChange={(e) =>
                  handleTestResultChange(
                    player.user_id,
                    'result',
                    e.target.value
                  )
                }
              />
            </TestResultTableRow>
          );
        })}
      </div>
    </div>
  );
}


javascript reactjs typescript
1个回答
0
投票

我认为按索引更新将是更新状态的最佳选择,下面添加了一个示例,请检查,这可能对您有帮助。 请检查handleChange功能

import { useState } from 'react';

export default function PageLanding() {
  const [players, setPlayers] = useState([
    {
      player: 'John',
      target: 0,
      result: 1,
    },
    {
      player: 'Doe',
      target: 0,
      result: 2,
    },
    {
      player: 'Sam',
      target: 0,
      result: 3,
    },
  ]);

  // Update players by Index
  const handleChange = (value, index) => {
    var oldValue = [...players];
    oldValue[index].target = value;
    setPlayers(oldValue);
  };
  return (
    <>
      <table>
        <thead>
          <tr>
            <td>Player</td>
            <td>Target</td>
            <td>Result</td>
          </tr>
        </thead>
        <tbody>
          {players.map((player, index) => (
            <tr key={index}>
              <td>{player.player}</td>
              <td>
                <input
                  type="text"
                  value={player.target}
                  onChange={(e) => handleChange(e.target.value, index)}
                />
              </td>
              <td>{player.result * player.target}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </>
  );
}

© www.soinside.com 2019 - 2024. All rights reserved.