将bool传递给子组件无法正常工作

时间:2019-06-18 17:06:50

标签: reactjs react-hooks

我试图让我的用户有选择地让文本框获取默认值。填写表格以记录交付的物品数量。可以为空,也可以根据订购的数量减去已经收到的数量自动计算应到达的商品数量。我可以算数学!

我有一个带有React Hooks的布尔集,当您单击链接时,它会切换。我希望这会导致重新渲染带有填充或未填充文本框的订单项,具体取决于在props集合中传递“ AutoFill”。似乎很简单。如果我将正确或错误的代码硬编码到该属性中,则就像梦一样。如果我改为插入变量,则完全失败。 我对React还是有些陌生,但我认为我有能力做到这一点。可能会丢失一些明显的内容或无法正确理解生命周期和渲染过程。

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

function App() {

  const [af, setAf] = useState(false);

  const theList = [
    { Id: 1, Quantity: 7, Received: 4 },
    { Id: 2, Quantity: 4, Received: 0 }
  ];

  const setVal = (id, val) => {
    console.log(`Value for Id ${id} was set by child to ${val}`);
  };

  return (
    <div>
      <div onClick={() => setAf(!af)}>Toggle</div>
      {theList.map((itm, idx) => {
        return (
          <LineItem onChange={setVal} key={idx} AutoFill={af} Data={itm} />
        );
      })}
    </div>
  );
}

function LineItem(props) {
  const [val, setVal] = useState(
    props.AutoFill ? props.Data.Quantity - props.Data.Received : undefined
  );

  const setValue = newVal => {
    setVal(newVal);
    props.onChange(props.Data.Id, newVal);
  };

  return (
    <>
      <p>Value: {val}</p>
      <p>
        <input
          type="number"
          value={val}
          onChange={e => setValue(e.target.value)}
        />
      </p>
    </>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

应用程序组件应显示组件列表。传入布尔值来决定是否进行总和并填充文本框。

如果我对AutoFill属性的值进行硬编码,则每次使用正确的数学运算时都可以使用,或者根据需要将其设置为空白。当我将变量放入时,它始终为空白-它从未在组件中预先填充文本框。

1 个答案:

答案 0 :(得分:0)

传递给useState的参数仅使用一次,因此,当您更改AutoFill prop的值时,不会再次评估状态。为此,您需要使用useEffect钩子

const [val, setVal] = useState(
    props.AutoFill ? props.Data.Quantity - props.Data.Received : undefined
  );


  useEffect(() => {
     if(props.AutoFill) {
        setVal(props.Data.Quantity - props.Data.Received)
     }
  }, [props.AutoFill, props.Data.Quantity, props.Data.Received]);

工作演示

const { useState, useEffect } = React;
function App() {

  const [af, setAf] = useState(false);

  const theList = [
    { Id: 1, Quantity: 7, Received: 4 },
    { Id: 2, Quantity: 4, Received: 0 }
  ];

  const setVal = (id, val) => {
    console.log(`Value for Id ${id} was set by child to ${val}`);
  };


  return (
    <div>
      <div onClick={() => setAf(!af)}>Toggle</div>
      {theList.map((itm, idx) => {
        return (
          <LineItem onChange={setVal} key={idx} AutoFill={af} Data={itm} />
        );
      })}
    </div>
  );
}

function LineItem(props) {
  const [val, setVal] = useState(
    props.AutoFill ? props.Data.Quantity - props.Data.Received : undefined
  );

  const setValue = newVal => {
    setVal(newVal);
    props.onChange(props.Data.Id, newVal);
  };


  useEffect(() => {
     if(props.AutoFill) {
        setVal(props.Data.Quantity - props.Data.Received)
     }
  }, [props.AutoFill, props.Data.Quantity, props.Data.Received]);


  return (
    <React.Fragment>
      <p>Value: {val}</p>
      <p>
        <input
          type="number"
          value={val}
          onChange={e => setValue(e.target.value)}
        />
      </p>
    </React.Fragment>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.3/umd/react-dom.production.min.js"></script>
<div id="root" />