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;
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