Search code examples
javascriptreactjstypescriptreact-hooksreact-component

How to set data in child component dynamically by using props in React?


I have solved one of my problem in this question for passing function as param

Now I am sending request to backend to add new record to db and I want to update the table immediately after adding new record by getting all items from backend.

Here is my parent App.js class having 2 component as MainPanel and TableFooterPanel:

function App() {

  const [customers, setCustomers] = useState([]);
  
  useEffect(() => {
    const fetchPostList = async () => {
      const response = await service.getCustomerList();
      setCustomers(response.data);
    };
    fetchPostList()
  }, []);

  const refreshTableData = () => {
    const fetchPostList = async () => {
      const response = await service.getCustomerList();
      setCustomers(response.data);
    };
    fetchPostList()
  }
  return (
    <div className="App">
      <h1>Customer List</h1>
      <MainPanel param={customers}/>
      <TableFooterPanel funcParam={refreshTableData}/>
    </div>
  );
}

export default App;

I am passing refresh function to TableFooterPanel which has a button to add new record and this function is triggered when a new record is added. Here is TableFooterPanel

function TableFooterPanel(props) {

    const [firstName, setFirstName] = useState('');
    const [lastName, setLastName] = useState('');

    const addNewCustomer = (name, surname) => {
        service.addCustomer(name, surname);
        props.funcParam();
    }

    return (

        <>
            <Card className='buttonFooter'>
                <Form className='buttonFooter'>
                    <input type="text" placeholder="First Name" defaultValue={firstName} onChange={e => setFirstName(e.target.value)}></input>
                    <input type="text" placeholder="Last Name" defaultValue={lastName} onChange={e => setLastName(e.target.value)}></input>
                    <Button onClick={() => addNewCustomer(firstName, lastName)}>Add</Button>
                </Form>
            </Card>

        </>

    );

}
export default TableFooterPanel;

And I want to refresh table data which lies in MainPanel:

function MainPanel(props) {

  const [customers, setCustomers] = useState([]);
  
  const deleteCustomer = (id) => {
    service.deleteCustomerById(id);
  }

  return (
    <ReactBootStrap.Table striped bordered hover>
        <thead>
          <tr>
            <th>ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Delete</th>
          </tr>
        </thead>
        <tbody>
          {props.param &&
            props.param.map((item) => (
              <tr key={item.id}>
                <td>{item.id}</td>
                <td>{item.firstName}</td>
                <td>{item.lastName}</td>
                <td><Button onClick={() => deleteCustomer(item.id)} ><FontAwesomeIcon icon={faTrashRestore} /></Button></td>
              </tr>   
            ))}
        </tbody>
      </ReactBootStrap.Table>
  );
}

What happens here is when I add a new record, the table data is not changing dynamically, but if I add second data then I sees the previous data and updating table but still not showing the last added data. How can I refresh data and send latest data to MainPanel?

export default MainPanel;

Solution

  • Your problem is with this section:

    const addNewCustomer = (name, surname) => {
      service.addCustomer(name, surname);
      props.funcParam();
    }
    

    It looks like you are calling the refresh function (props.funcParam()) before the addCustomer service is finished being called (since this is a Promise). That is causing your fetch to start fetching the existing data BEFORE it is updated.

    You'll need to make the function asynchronous and then await it like this:

    const addNewCustomer = async (name, surname) => {
      await service.addCustomer(name, surname);
      props.funcParam();
    }
    

    Now your function will wait for service.addCustomer to finish executing before executing the refresh fuction.