Search code examples
reactjsformsreduxmodal-dialogmaterial-table

How can refresh data in a table using react redux and a modal form?


I'm facing an issue with refreshing data in a table using react/redux and a form. What I need to do here is to fill a modal form, than submit to my backend and then refreshing the table using setState. I can do all the things so rendering the table, showing the modal, submitting data but I can't refresh data in the table when modal is closed. How can I get this result with redux?

import React, {useState} from 'react';
import ContainerHeader from 'components/ContainerHeader/index';
import IntlMessages from "../../../util/IntlMessages";
import {useDispatch, useSelector, shallowEqual} from 'react-redux';
import {
    getBanksFromBackend,
    storeBankBackend,
    updateBankBackend,
    deleteBankBackend,
} from '../../../actions';
import MaterialTable, {MTableToolbar} from "material-table";
import CardBox from "../../../components/CardBox";
import FormDialog from "./FormDialog";
import TextFields from "./TextFields";

const BanksPage = ({match}) => {
    const dispatch = useDispatch();
    const allBanks = useSelector(state => state.banks, shallowEqual);

    const [state, setState] = useState({
        columns: [
            {
                title: 'Avatar',
                field: 'imageUrl',
                render: rowData => <img src={rowData.imageUrl} style={{width: 30, borderRadius: '50%'}}/>
            },
            {title: 'ID', field: 'id', editable: 'never'},
            {title: 'Bank Name', field: 'bnk_name'},
            {title: 'Bank Iban', field: 'bnk_iban'},
            {title: 'Bank BIC', field: 'bnk_bic'},
        ],
        data: allBanks.banks.map(bank => {
            return (
                {
                    imageUrl: 'https://img.icons8.com/office/80/000000/user.png',
                    id: bank.id,
                    bnk_name: bank.bnk_name,
                    bnk_iban: bank.bnk_iban,
                    bnk_bic: bank.bnk_bic,
                }
            )
        })
    });


    return (
        <div className="app-wrapper">
            <ContainerHeader match={match} title={<IntlMessages id="pages.banks"/>}/>
            <div className="row">

                <CardBox styleName="col-lg-12">
                    <MaterialTable
                        title="Users Table"
                        columns={state.columns}
                        data={state.data}
                        options={{
                            exportButton: true,
                            grouping: true,
                            selection: true
                        }}
                        components={{
                            Toolbar: props => (
                                <div>
                                    <MTableToolbar {...props} />
                                    <div style={{padding: '0px 10px'}}>
                                        <div className="card d-inline-block">
                                            <FormDialog {...state}/>
                                        </div>
                                    </div>
                                </div>
                            ),
                        }}
                    />
                </CardBox>

             

            </div>

        </div>
    )

}

export default BanksPage;

This is the modal component

import React, {useState} from 'react';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
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 {useDispatch, useSelector, shallowEqual} from "react-redux";
import {getBanksFromBackend, storeBankBackend} from "../../../actions";


const FormDialog = (props) => {
    console.log('Proprietà passate al form: ', props);

    const dispatch = useDispatch();

    const initModalState = {
        open: false,
    };
    const [modalState, setModalState] = useState(initModalState);

    const [bankName, setBankName] = useState('');
    const [bankIban, setBankIban] = useState('');
    const [bankBic, setBankBic] = useState('');

    const [tableState, setTableState] = useState(props);
    console.log('Stato iniziale Tabella:', tableState);

    const handleClickOpen = () => {
        setModalState({open: true})
    };

    const handleRequestClose = () => {
        setModalState({open: false})
    };


    return (
        <div>
            <Button variant="contained" className="bg-primary text-white" onClick={() => handleClickOpen()}>Add
                Bank</Button>
            <form>
                <Dialog open={modalState.open} onClose={() => handleRequestClose()}>
                    <DialogTitle>Subscribe</DialogTitle>
                    <DialogContent>
                        <DialogContentText>
                            Add Bank from Form.
                        </DialogContentText>

                        <TextField
                            autoFocus
                            margin="dense"
                            id="bnk_name"
                            label="Bank Name"
                            type="text"
                            fullWidth
                            onChange={(event) => setBankName(event.target.value)}
                            defaultValue={bankName}
                        />
                        <TextField
                            autoFocus
                            margin="dense"
                            id="bnk_iban"
                            label="Bank Iban"
                            type="text"
                            fullWidth
                            onChange={(event) => setBankBic(event.target.value)}
                            defaultValue={bankIban}
                        />
                        <TextField
                            autoFocus
                            margin="dense"
                            id="bnk_bic"
                            label="Bank BIC"
                            type="text"
                            fullWidth
                            onChange={(event) => setBankIban(event.target.value)}
                            defaultValue={bankBic}
                        />

                    </DialogContent>

                    <DialogActions>
                        <Button onClick={() => handleRequestClose()} color="secondary">
                            Cancel
                        </Button>
                        <Button onClick={() => handleRequestClose()} color="primary">
                            Submit
                        </Button>

                        <Button onClick={() => new Promise((resolve) => {
                            setTimeout(() => {
                                resolve();
                                dispatch(storeBankBackend
                                    ({
                                            bnk_name: bankName,
                                            bnk_iban: bankIban,
                                            bnk_bic: bankBic
                                        }
                                    )
                                );
                                dispatch(getBanksFromBackend());
                                handleRequestClose();
                            }, 2000)
                        })} color="primary">
                            Submit Bank
                        </Button>

                    </DialogActions>
                </Dialog>
            </form>
        </div>
    );

}

export default FormDialog;


Solution

  • I think you're cloning redux states in BanksPage functional component. In react components states are defined in constructor, so you're assigning them just on first render.

    Later, dispatching in FormDialog component (maybe) works by succesfully calling the action (as orangespark suggested are you sure dispatch is working? You should show us your actions and reducer), but the components do not update because you're rendering a state clone memoized in BanksPage component.

    Suggest you to try moving out columns and data objects from the state hook, it shouldn' t be necessary when working just with redux states, and go on by assigning them to variables