Событие onChange не запускается при первом вводе - PullRequest
0 голосов
/ 02 августа 2020

Я новичок в React, и у меня есть эта регистрация (родительский компонент), где есть инвентарь (дочерний компонент), и я меняю состояние инвентаря, как только пользователь вводит количество элемента, который они удерживайте, чтобы я мог их зарегистрировать

Но onChange, похоже, задерживается, я ввожу, например, 4 бутылки с водой, и консоль регистрирует мне значение по умолчанию, только когда я ввожу количество для другого элемента, такого как еда, он отображает мне 4 бутылки с водой и 0 еды: (

Это то, с чем я работаю ...

Дочерний компонент:

import React from "react";
import { Col, Row, FormGroup, Label, Input } from "reactstrap";

import waterIcon from "./../assets/water.png";
import soupIcon from "./../assets/food.png";
import medsIcon from "./../assets/aid.png";
import weaponIcon from "./../assets/gun.png";

function Inventory({ onSubmitInventory, currentInventory }) {
  const onChangeWater = (e) => {
    const newInventory = { ...currentInventory, water: e.target.value };
    onSubmitInventory(newInventory);
  };

  const onChangeSoup = (e) => {
    const newInventory = { ...currentInventory, soup: e.target.value };
    onSubmitInventory(newInventory);
  };

  const onChangeMeds = (e) => {
    const newInventory = { ...currentInventory, meds: e.target.value };
    onSubmitInventory(newInventory);
  };

  const onChangeWeapon = (e) => {
    const newInventory = { ...currentInventory, weapon: e.target.value };
    onSubmitInventory(newInventory);
  };

  return (
    <FormGroup>
      <Row className="justify-content-center text-center border-top pt-3">
        <Col xs="3">
          <img src={waterIcon} alt="Water" />
          <Label for="inventoryWater">Fiji Water:</Label>
          <Input
            type="number"
            name="inventoryWater"
            id="inventoryWater"
            placeholder="Enter ammount..."
            onChange={onChangeWater}
          />
        </Col>
        <Col xs="3">
          <img src={soupIcon} alt="Soup" />
          <Label for="inventorySoup">Campbell Soup:</Label>
          <Input
            type="number"
            name="inventorySoup"
            id="inventorySoup"
            placeholder="Enter ammount..."
            onChange={onChangeSoup}
          />
        </Col>
        <Col xs="3">
          <img src={medsIcon} alt="Aid" />
          <Label for="inventoryMeds">First Aid Pouch:</Label>
          <Input
            type="number"
            name="inventoryMeds"
            id="inventoryMeds"
            placeholder="Enter ammount..."
            onChange={onChangeMeds}
          />
        </Col>
        <Col xs="3">
          <img
            className="d-block"
            style={{ margin: "0 auto" }}
            src={weaponIcon}
            alt="Gun"
          />
          <Label for="inventoryWeapon">AK47:</Label>
          <Input
            type="number"
            name="inventoryWeapon"
            id="inventoryWeapon"
            placeholder="Enter ammount..."
            onChange={onChangeWeapon}
          />
        </Col>
      </Row>
    </FormGroup>
  );
}

export default Inventory;

Родительский компонент:

import React, { useState } from "react";
import { Col, Row, Button, Form, Label, Input } from "reactstrap";
import { useForm } from "react-hook-form";

import Inventory from "./Inventory";
import MapContainer from "./MapContainer";

function Register() {
  const [lonlat, setLonlat] = useState("");
  const onMarkerChange = (lonlat) => {
    setLonlat(lonlat);
  };

  const [inventory, setInventory] = useState({
    water: 0,
    soup: 0,
    meds: 0,
    weapon: 0,
  });
  const onSubmitInventory = (newInventory) => {
    setInventory(newInventory);
    console.log(inventory);
  };

  const { register, handleSubmit, errors } = useForm();
  const onSubmit = (data) => {
    console.log(inventory);
    const requestOptions = {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ name: data.personName }),
    };
    console.log(data);
  };

  return (
    <Form
      id="registerForm"
      name="registerForm"
      onSubmit={handleSubmit(onSubmit)}
    >
      <h4>New Person</h4>
      <Row className="border-top pt-4">
        <Col xs="8">
          <Label for="personName">Your name:</Label>
          <Input
            className="gray-input"
            type="text"
            name="name"
            id="personName"
            placeholder="Enter your name here..."
            innerRef={register}
          />
        </Col>
        <Col xs="2" className="text-center">
          <Label for="personAge">Age:</Label>
          <Input
            className="gray-input"
            type="number"
            name="age"
            id="personAge"
            placeholder="Enter age..."
            innerRef={register}
          />
        </Col>
        <Col xs="2" className="text-center">
          <Label for="personGender">Gender:</Label>
          <Input
            type="select"
            name="gender"
            id="personGender"
            innerRef={register}
          >
            <option defaultValue disabled>
              -
            </option>
            <option>F</option>
            <option>M</option>
          </Input>
        </Col>
      </Row>
      <Row>
        <Col xs="12">
          <Input
            hidden
            id="personLatLon"
            name="personLatLon"
            type="text"
            defaultValue={lonlat}
            innerRef={register}
          />
          <MapContainer onMarkerChange={onMarkerChange} />
        </Col>
      </Row>
      <h4>Inventory</h4>
      <Inventory
        onSubmitInventory={onSubmitInventory}
        currentInventory={inventory}
      />
      <Button
        outline
        color="secondary"
        className="mt-2"
        type="submit"
        form="registerForm"
      >
        Submit
      </Button>
    </Form>
  );
}

export default Register;

РЕДАКТИРОВАТЬ: Обновленный код с советами из ответов, все еще сталкивается с той же проблемой: (* ​​1013 *

Ответы [ 2 ]

2 голосов
/ 02 августа 2020

Единственная проблема, которую я вижу в вашем коде, заключается в том, что вы пытаетесь передать второй аргумент в setInventory. Я не верю, что это работает с хуками, как с компонентами класса. Когда я пытаюсь ввести это в машинописный текст, он мгновенно вызывает ошибку.

Просто передайте фактические данные, которые вы пытаетесь отправить, а затем позвоните onSubmitInventory(inventory), например:

  const onChangeWeapon = (e) => {
    const newInventory = {...inventory, weapon: e.target.value};
    setInventory(newInventory);
    onSubmitInventory(newInventory);
  };

Если вы нужно дождаться следующего рендеринга, чтобы вызвать onSubmitInventory, это должно быть useEffect в родительском элементе. Мой следующий вопрос: почему родителю нужно состояние, а у ребенка оно тоже есть состояние? Возможно, его следует поднять. Но я не уверен в этом, не увидев родителя.

Edit: ваша проблема только с console.log? Если вы запустите

const [state, setState] = useState(true);
// ...
setState(false);
console.log(state); // outputs true.

, значение состояния не изменится до следующего рендера. Вызов setState вызовет новый рендеринг, но пока это не произойдет, старое значение останется. Добавьте console.log состояния в родительский элемент только в теле, как здесь

const [inventory, setInventory] = useState({
    water: 0,
    soup: 0,
    meds: 0,
    weapon: 0,
  });
console.log('I just rendered, inventory: ', inventory);

Вы увидите обновления!

Тот факт, что значение состояния не меняется, может укусить вы в этом случае:

const [state, setState] = useState(true); // closes over this state!
// ...
setState(!state); // closes over the state value above
setState(!state); // closes over the same state value above
// state will be false on next render

Поэтому я использую эту форму, если есть возможность, я дважды вызываю setState перед рендерингом:

const [state, setState] = useState(true);
// ...
setState(state => !state);
setState(state => !state);
// state will be true on next render
1 голос
/ 02 августа 2020

Внутри родительского компонента onSubmitInventory вы назвали аргумент inventory, но он уже существует в родительской области. Я предлагаю переименовать этот newInventory, чтобы было понятно, на что вы ссылаетесь.

Кроме того, похоже, что вы отслеживаете инвентарь как в родительском, так и в дочернем состоянии. Сохраните его в родительском элементе и передайте дочернему элементу как prop / props.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...