Crusaderpyro
Crusaderpyro

Reputation: 2242

React function component parent state change does not re-render child component

I have a parent react function component (Products) which shows a list of products and with a state productInfo which is passed as a prop to the child component (AddEditProductModal)

const Products = () => {
  
  const [isEditModalVisible, setIsEditModalVisible] = useState(false);
  const [productInfo, setProductInfo] = useState({});

  const showEditModal = async (currentProductInfo) => {
       console.log('edit called for key ',currentProductInfo.key)
       setIsEditModalVisible(true);
       setProductInfo(prevProductInfo => {
         return {...prevProductInfo, ...currentProductInfo};
        });
  };
  
  useEffect(() => {
    setIsEditModalVisible(false);
    setProductInfo({})
  }, []);


  return (
    <>
       <AddEditProductModal
        title="Edit Product"
        visible={isEditModalVisible}
        productInfo={productInfo}
        onOk={handleOk}
        onCancel={handleCancel}
        onFinish={onFinish}
      />
      
      //Table components with columns/actions per row go here
   
      
    </>
  );
};

export default Products;

The child component AddEditProductModal is an antd Modal/Popup which fills the form with prefilled values chosen for current product row as shown below.

const AddEditProductModal = ({ title, visible, productInfo, onOk, onCancel, onFinish }) => {

  return (
    <Modal
     title={title}
     visible={visible}
     onOk={onOk}
     onCancel={onCancel}
     >
      <Form
        name="basic"
        labelCol={{
          span: 8,
        }}
        wrapperCol={{
          span: 16,
        }}
        onFinish={onFinish}
        initialValues = {productInfo}
      >
        <Form.Item
          label="Key"
          name="key"
        >
          <Input disabled={true} />
        </Form.Item>
        <Form.Item
          label="Image"
          name="image"
          rules={[
            {
              required: true,
              message: "Please input image!",
            },
          ]}
        >
          <Input />
        </Form.Item>

        <Form.Item
          label="Name"
          name="name"
          rules={[
            {
              required: true,
              message: "Please input name!",
            },
          ]}
        >
          <Input />
        </Form.Item>
        <Form.Item
          label="Price"
          name="price"
          rules={[
            {
              required: true,
              message: "Please input price!",
            },
          ]}
        >
          <Input  />
        </Form.Item>
        <Button type="primary" htmlType="submit">
          Submit
        </Button>
      </Form>
    </Modal>
  );
};
export default AddEditProductModal;

The productInfo is an object containing props as shown below:

{"key":19,"name":"Cooker","image":"https://.....d16bfa6d9c2e010cadc3fe6885448cbd.jpg_720x720q80.jpg","price":123}

When I click on any row's Edit button, the AddEditProductModal shows correct default values for the product. But when I click on another product/row, the AddEditProductModal still shows old values even though the productInfo state (seen in the profiler) has changed. Basically, the productInfo state has changed in the parent but the child has not re-rendered is what I am thinking.

Can anyone help why the modal shows the info on the first click but second time, fails to re-render and shows old product info ?

Upvotes: 1

Views: 1872

Answers (2)

LeeKlaus
LeeKlaus

Reputation: 299

Yes, you are right! First, antd Form's API initialValues only works when it is initialized or reset. Second, antd Modal won't destroy after the close. So there is the result you said.

method A: do what you said,

useEffect(() => {
  form.setFieldsValue(productInfo);
}, [productInfo]);

method B: destroyOnClose property of Modal set true will also solve your issue, but this is not a good choice!

const AddEditProductModal = ({ title, visible, productInfo, onOk, onCancel, onFinish }) => {

  return (
    <Modal
     title={title}
     visible={visible}
     onOk={onOk}
     onCancel={onCancel}
     +destroyOnClose+
    >
      ...

Upvotes: 2

Crusaderpyro
Crusaderpyro

Reputation: 2242

I got the answer to my problem. Rather than react, this seemed like an issue with the antd Form component initialValues. Seems like the initialValues does not change and we need to explicitly update the values. Adding the following to my AddEditProductModal solved my issue:

const [form] = Form.useForm();

useEffect(() => {
  form.setFieldsValue(productInfo);
}, [productInfo]);

Hope this helps some antd user some day.

Upvotes: 0

Related Questions