Рендеринг React props выполняется с опозданием на шаг

#javascript #reactjs #react-native

#javascript #reactjs #react-native

Вопрос:

У меня есть следующее, которое изменяет значения, но оно всегда на шаг позади. Например, когда вы нажимаете на «оплачено: ложь» для клиента, оно меняется на true, но приложение не выполняет повторный запуск, и вам нужно обновить что-то еще в приложении, чтобы увидеть изменения. Есть ли простой способ исправить это в React? Я не знаю, как исследовать то, что я ищу, поэтому точка в правильном направлении очень поможет.

 const [receipt, setReceipt] = useState(receiptData);
  // const [currentReceipt, setCurrentReceipt] = useState({});
  // For some reason I do not know yet, everything is working but this and onSubmitFromApp are one step behind.
  const handlePaid = (index) => {
    for (let receiptPaid in receiptData) {

      if (receiptPaid === index) {
        receiptPaid.paid = !receiptPaid.paid;
        console.log(receiptPaid);
      }
    }
    setReceipt(receiptData);
  }
  

Ссылка на полный код: https://codesandbox.io/s/korilla-receipts-starter-forked-01xz0?file=/src/App.js:206-675

Комментарии:

1. React повторно отображает компоненты при изменении состояния. Ваша handlePaid функция не обновляет состояние. Он просто изменяет объект. Это не приведет к повторному рендерингу: const handlePaid = (index) => { props.receiptsArr[index].paid = !props.receiptsArr[index].paid; } Вам нужно сохранить свои значения в состоянии (или что-то аналогичное, например, хранилище Redux) и правильно обновить его, а не просто мутировать объекты. Кроме того, handlePaid функция в вашем вопросе, похоже, никогда не вызывается, поскольку Receipts компонент использует другую handlePaid функцию.

2. Попробуйте это : setReceipt([... receiptPaid]);

Ответ №1:

Ваш подход довольно странный и включает мутации. Вам лучше сделать что-то подобное (я удалил материал формы, потому что это не связано):

 // App.js
export default function App() {
  const [receipts, setReceipts] = useState(receiptData);

  // Map over the current state, not the imported array
  const handlePaid = (id) => {
    setReceipts(
      receipts.map((receipt) =>
        receipt.id === id ? { ...receipt, paid: !receipt.paid } : receipt
      )
    );
  };
  
  return (
    <div className="App">
      <Receipts receiptsArr={receipts} handlePaid={handlePaid} />
    </div>
  );
}
  

 // Receipts.js
const Receipts = (props) => {
  const receiptMap = props.receiptsArr.map((receipt, index) => {
    return (
      <Receipt
        ...
        handlePaid={() => props.handlePaid(receipt.id)}
      />
    );
  });
  return <div className="container">{receiptMap}</div>;
};
  

 // Receipt.js
const Receipt = (props) => {
    return (
      ...
      <span onClick={props.handlePaid} >Paid: {props.paid ? 'true' :  'false'}</span>
    </div>
    )
}
  

Вы можете проверить песочницу здесь