简体   繁体   English

反应从子组件重新渲染父组件不起作用

[英]React re-render parent from child component not working

I have a parent component (DevicePage) that loads multiples of a child component (Device).我有一个父组件(DevicePage),它加载多个子组件(设备)。 In the child component, I have buttons to check-in and check-out a device.在子组件中,我有用于签入和签出设备的按钮。 When I click on the buttons on the DevicePage, the page doesn't re-render and the button states don't change.当我单击 DevicePage 上的按钮时,页面不会重新呈现,按钮状态也不会改变。

I've tried some suggested answers where you pass a function to the child that the child can call to update a state on the parent (see here How to re-render parent component from child component ) but it doesn't work in my case and not sure why.我尝试了一些建议的答案,您将 function 传递给孩子,孩子可以调用以更新父级上的 state (请参阅此处如何从子组件重新渲染父组件),但在我的情况下它不起作用不知道为什么。

Here's what I have:这是我所拥有的:

Parent家长

  const [devices, setDevices] = useState();
  const [count, setCount] = useState(0);

  useEffect(() => {
    setCount(1)
    DeviceService.getAll()
      .then(res => {
        if(res.data.length > 0) {
          setDevices(res.data);
        }
      });
  }, [])

  function checkoutDevice(id) {
    console.log("About to checkout device");
    DeviceService.checkoutDevice(id)
      .then(res => {
        console.log("Device checked out")
      })
      .catch(err => "Error checking out device: " + err);
  }

  function checkinDevice(id) {
    DeviceService.checkinDevice(id)
      .then(res => {
        console.log("Device checked in")
      })
      .catch(err => "Error checking out device: " + err);
  }

  function devicesList() {
    if(devices) {
      return devices.map(currDevice => {
        return <Device device={currDevice} checkoutDevice={checkoutDevice} checkinDevice={checkinDevice} key={currDevice._id} />;
      });
    }
  }

  return (
    <div>
      <table className="table">
        <thead className="thead-light">
          <tr>
            <td>Tag</td>
            <td>Category</td>
            <td>Make</td>
            <td>Model</td>
          </tr>
        </thead>
        <tbody>
          {devicesList()}
        </tbody>
      </table>
    </div>
  )
}

Child孩子

return (
    <tr>
    <td><Link to={"/devices/" + props.device._id}>{props.device.tag}</Link></td>
    <td>{props.device.category}</td>
    <td>{props.device.make}</td>
    <td>{props.device.modelName}</td>
    {
      props.device.available?
        <>
          <td>
            <button type="button" className="btn btn-primary" onClick={() => {props.checkoutDevice(props.device._id)}}>Checkout</button>
          </td>
        </>
        :
        <>
          <td>
            <button type="button" className="btn btn-primary" onClick={() => {props.checkinDevice(props.device._id)}}>Checkin</button>
          </td>
        </>
    }
    {
      currUser.isAdmin?
        <>
          <td>
            <Link to={{pathname: "/devices/edit/" + props.device._id, 
              state: {
                tag: props.device.tag
              }}}>
              edit
            </Link>
          </td>
        </>
      : 
        null
    }
  </tr>
  )

Your problem is "the page doesn't re-render and the button states don't change.", and my assumption is when you click on "Checkout" button, you want it to change to "Checkin" button and vice versa.您的问题是“页面不会重新呈现并且按钮状态不会改变。”,我的假设是当您单击“结帐”按钮时,您希望它更改为“签入”按钮,反之亦然。 Look at this code block in the Device component:查看 Device 组件中的这个代码块:

    {
      props.device.available?
        <>
          <td>
            <button type="button" className="btn btn-primary" onClick={() => {props.checkoutDevice(props.device._id)}}>Checkout</button>
          </td>
        </>
        :
        <>
          <td>
            <button type="button" className="btn btn-primary" onClick={() => {props.checkinDevice(props.device._id)}}>Checkin</button>
          </td>
        </>
    }

With this logic, in order to change the button, you have to change the device.available, which your code above doesn't.使用此逻辑,为了更改按钮,您必须更改 device.available,而您的上面的代码没有。 To do that I would recommend 2 solutions:为此,我会推荐 2 个解决方案:

  1. Lazy way, with bad performance: after call checkin/checkout api success, fetch the whole device list again懒惰的方式,性能不佳:在调用 checkin/checkout api 成功后,再次获取整个设备列表
  2. More work but better: after checkin/checkout api call success, update the device list and setDevices again.更多工作但更好:签入/签出 api 调用成功后,更新设备列表并再次设置设备。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM