skip to Main Content

Summary: I have a component that contains an Antd Table component. The Antd Table component is created initially based on the original userData that is generated using a fetch request. The data is loaded initially and set using setState(fetchedData) calling render() to display appropriately. This works.

Using the NiceModal library, I present a new modal component and pass in a doCompelte closure that will then setstate again with the updated data. From here, the render() method is called again. I log the updated userData in the render() method before the data is loaded and it shows the data is updated and it confirms that render() is called with the new data. But, the visual display never actually loads on the screen.

At this point, I stopped taking user input from the Modal and tried giving it direct values, as shown in EditModal.jsx. This still doesn’t work and I’m unsure of why.

Question: Why is my component render() method called, new data printed correctly, but the React Antd Table is not loading the new data?

Note: I did try creating a local variable inside the render() method that accesses userData at that given time but this also doesn’t update the table.

UPDATE 1: You can see that the first name is "Mrs." then it gets hardcode changed to "GPRLEJAF" inside the showEditModal() function which now does NOT show a modal, it just changes the value and sets the state.

Pre

You’ll see that the re-rendering shows the update in the console but the table is never updated.

Post

UserList.jsx

import React, { useEffect } from 'react';
import NiceModal, { useModal } from '@ebay/nice-modal-react';
import { Button, Table } from 'antd';
import { EditOutlined } from '@ant-design/icons';
import AddCircle from '../../../node_modules/material-jsx-icons/dist/icons/add_circle';
import { useLocation } from 'react-router-dom';
import AddModal from './AddModal'
import EditModal from './EditModal'
import "./Table.css";
import 'bootstrap/dist/css/bootstrap.min.css';
import data from '../../mock';

function search() {
  
}

function withMyHook(Component) {
  return function WrappedComponent(props) {
    const myHookValue = useLocation();
    return <Component {...props} myHookValue={myHookValue} />;
  }
}

class UserList extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      userData: [],
    }
  }

  self = this;
  columns = [
    {
      title: 'First Name',
      dataIndex: 'First_Name',
      width: '10%',
      align: 'center',
    },
    {
      title: 'Last Name',
      dataIndex: 'Last_Name',
      width: '10%',
      align: 'center',
    },
    {
      title: 'Address',
      dataIndex: 'Address',
      width: '20%',
      align: 'center',
    },
    {
      title: 'Billed',
      dataIndex: 'Billed',
      width: '5%',
      align: 'center',
    },
    {
      title: 'Work Date',
      dataIndex: 'Work_Date',
      width: '12%',
      align: 'center',
    },
    {
      title: 'Last Modified Date',
      dataIndex: 'Table_Date',
      width: '12%',
      align: 'center',
    },  
    {
      title: 'Notes',
      dataIndex: 'Notes',
      width: '32%',
      align: 'center',
    },
    {
      title: 'Actions',
      width: '5%',
      align: 'center',
      dataIndex: 'taco',
      render: (_, value) => <Button type="link" icon={<EditOutlined />} onClick={() => this.showEditModal(value)}/>
    },
  ];

  showEditModal(value) {
    /*
    var index = this.userData.findIndex(item => item == value);
    NiceModal.show(EditModal,  { data: value, onEdit: (updatedUser) => {
      this.userData[index] = updatedUser; // Update current user with updated data
      this.setState([...this.userData]); // Re-Render with new data
    }});
    */
    this.userData[0].First_Name = "Random Name";
    this.setState([this.userData]);
  };

  iconStyles = {
    width: '25px',
    fill: '#ffffff',
    justifyContent: 'center',
    alignItems: 'center',
    float: 'left',
    marginRight: '5px',
  };

  componentDidMount() {
    console.log("Updating");
    const token = this.props.myHookValue.state['token'];
    console.log("Token", this.props.myHookValue.state['token']);
    let response = fetch('https://x7n8z7pgo5.execute-api.us-east-1.amazonaws.com/dev', {
      headers: {
        "Authorization": token
      }
    })
    .then(response => response.json())
    .then(data => {
      console.log("Retrieved Data", data);
      this.userData = data["Items"];
      console.log("User Data", this.userData);
      this.setState([...data["Items"]]); //re-renders data
    })
    .catch(err => console.log(err));
  }

  showAddModal = () => {
    NiceModal.show(AddModal, { component: this });;
  };

  render() {
    const curData = this.userData;
    console.log("Rerendering", curData);
    return <div>
        <div className="container-xl">
            <div className="table-responsive">
                <div className="table-wrapper">
                    <div className="table-title">
                        <div className="row">
                            <div className="col-sm-6">
                                <h2>Manage Clients</h2>
                            </div>
                            <div className="col-sm-6">
                            {<Button className="btn btn-success" type="primary" onClick={this.showAddModal}>
                              <AddCircle style={this.iconStyles}/> Add New Client
                            </Button>}
                            </div>
                        </div>
                    </div>
                    <input id="search" type="text" placeholder="Search..." onKeyUp={search}/>
                    <Table
                      size="small"
                      rowKey="id"
                      pagination={false}
                      columns={this.columns}
                      dataSource={curData}
                      style={{ marginTop: '20px' }}
                    />
                    </div>
                </div>
                <div>
            </div>
        </div>
    </div>
  }
}

export default withMyHook(UserList);

EditModal.jsx

import { Modal } from 'antd';
import NiceModal, { useModal } from '@ebay/nice-modal-react';
import Dialog from '@material-ui/core/Dialog';
import DialogActions from '@material-ui/core/DialogActions';
import DialogContent from '@material-ui/core/DialogContent';
import DialogContentText from '@material-ui/core/DialogContentText';
import DialogTitle from '@material-ui/core/DialogTitle';
import { FilePicker, TextInput } from 'evergreen-ui';
import TextArea from 'antd/lib/input/TextArea';
import TextField from '@material-ui/core/TextField';
import { Button } from 'antd';
import React, { useState } from 'react';

function textInputStyles(height='40px') {
    return {
        width: '350px',
        fontSize: '20px',
        height: height,
    }
}

export default NiceModal.create(({ data, onEdit }) => {
    const user = data;

    const [firstName, setFirstName] = useState(user.First_Name);
    const [lastName, setLastName] = useState(user.Last_Name);
    const [address, setAddress] = useState(user.Address);
    const [billed, setBilled] = useState(user.Billed);
    const [workDate, setWorkDate] = useState(user.Work_Date);
    const [notes, setNotes] = useState(user.Notes);

    const modal = useModal();
    return (
        <Dialog
            open={modal.visible}
            onClose={() => {
            modal.hide();
            }}
            TransitionProps={{
                onExited: () => modal.remove(),
            }}
        >
        <DialogTitle id="edit">{"Edit Client"}</DialogTitle><hr></hr>
        <DialogContent>
            <DialogContentText id="edit_first_name">
            First Name 
            </DialogContentText>
            <DialogContentText>
            <TextInput
                style={textInputStyles()}
                defaultValue={firstName}
                onChange={(e) => setFirstName(e.target.value)}
            />
            </DialogContentText>
            <DialogContentText id="edit_last_name">
            Last Name 
            </DialogContentText>
            <DialogContentText>
            <TextInput
                style={textInputStyles()}
                defaultValue={lastName}
                onChange={(e) => setLastName(e.target.value)}
            />
            </DialogContentText>
            <DialogContentText id="edit_address">
            Address
            </DialogContentText>
            <DialogContentText>
            <TextInput
                style={textInputStyles()}
                defaultValue={address}
                onChange={(e) => setAddress(e)}
            />
            </DialogContentText>
            <DialogContentText id="edit_billed">
            Billed
            </DialogContentText>
            <DialogContentText>
            <TextInput
                style={textInputStyles()}
                defaultValue={billed}
            />
            </DialogContentText>
            <DialogContentText id="edit_work_date">
            Work Date
            </DialogContentText>
            <DialogContentText>
            <TextField
                id="date"
                label=""
                type="date"
                InputLabelProps={{
                shrink: true,
                }}
                defaultValue={new Date(workDate).toISOString().substring(0, 10)}
            />
            </DialogContentText>
            <DialogContentText id="edit_last_modified_date">
            Today's Date
            </DialogContentText>
            <DialogContentText>
            <TextInput
                style={textInputStyles()}
                value={new Date().toDateString().split(' ').slice(1).join(' ')}
                editable={false}
            />
            </DialogContentText>
            <DialogContentText id="edit_notes">
            Notes
            </DialogContentText>
            <DialogContentText>
            <TextArea
                style={textInputStyles(175)}
                editable={false}
                defaultValue={notes}
            />
            </DialogContentText>
            <DialogContentText>
            Invoice
            </DialogContentText>
            <DialogContentText>
            <FilePicker>
                onClick={}
            </FilePicker>
            </DialogContentText>
        </DialogContent>
        <DialogActions style={{backgroundColor:'#D3D3D3', justifyContent: 'space-between'}}>
            <Button onClick={() => modal.hide()} className="btn" style={{backgroundColor:'red', width: '25%'}}>
            Cancel
            </Button>
            <Button onClick={() => {
                modal.hide();
                const updatedUser = {
                    'Address': 'asd',
                    'First_Name': 'asd',
                    'Billed': '123',
                    'Index': user.Index,
                    'Last_Name': 'fadsad',
                    'Notes': 'sdad',
                    'Table_Date': new Date(workDate).toISOString().substring(0, 10),
                    'Work_Date': workDate
                };
                onEdit(updatedUser);
                
            }} className="btn" style={{backgroundColor: '#47b300', color:'white', width: '25%', float:'right'}}>
            Add
            </Button>
        </DialogActions>
        </Dialog>
    );
});

2

Answers


  1. Chosen as BEST ANSWER

    Antd Tables require a copy of the data to be able to dynamically update the table.

      render() {
        if (typeof this.userData !== 'undefined') {
          var copy = JSON.parse(JSON.stringify(this.userData));
          console.log(copy);
          return <div>
              <div className="container-xl">
                  <div className="table-responsive">  
                      <div className="table-wrapper">
                          <div className="table-title">
                              <div className="row">
                                  <div className="col-sm-6">
                                      <h2>Manage Clients</h2>
                                  </div>
                                  <div className="col-sm-6">
                                  {<Button className="btn btn-success" type="primary" onClick={this.showAddModal}>
                                    <AddCircle style={this.iconStyles}/> Add New Client
                                  </Button>}
                                  </div>
                              </div>
                          </div>
                          <input id="search" type="text" placeholder="Search..." onKeyUp={search}/>
                          <Table
                            size="small"
                            rowKey="id"
                            pagination={false}
                            columns={this.columns}
                            dataSource={copy}
                            style={{ marginTop: '20px' }}
                          />
                          </div>
                      </div>
                      <div>
                  </div>
              </div>
          </div>
        }
        return <div>
          Loading
        </div>
      }
    

  2. Maybe here in componentDidMount and ShowEditModal (but we don’t the server response format) in UserList component

    componentDidMount() {
        console.log("Updating");
        const token = this.props.myHookValue.state['token'];
        console.log("Token", this.props.myHookValue.state['token']);
        let response = fetch('https://x7n8z7pgo5.execute-api.us-east-1.amazonaws.com/dev', {
          headers: {
            "Authorization": token
          }
        })
        .then(response => response.json())
        .then(data => {
          console.log("Retrieved Data", data);
          this.userData = data["Items"];
          console.log("User Data", this.userData);
          //this.setState([...data["Items"]]); //re-renders data
          this.setState({userData: data["Items"]}); //re-renders data
          //or
         this.setState({...data["Items"]});
        })
        .catch(err => console.log(err));
      }
    
    
    showEditModal(value) {
        var index = this.userData.findIndex(item => item == value);
        NiceModal.show(EditModal,  { data: value, onEdit: (updatedUser) => {
          this.userData[index] = updatedUser; // Update current user with updated data
          //this.setState([...this.userData]); // Re-Render with new data
         this.setState({userData: this.userData});
        //or
        this.setState({...this.userData});
        }});
      };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search