Reputation: 79
I'm using redux with react, In my react state I'm assigning some state properties to the props but in my state the accounts are changing but the loading property doesn't change, I also tried to update the state in componentdidupdate but when I try to do that I get maximum update depth exceeded
In AllAccounts the accounts property is updating when the accounts are done fetching and the props change but the same doesn't happen for the loading property, It is set to the first value when it changes when it is set to true, The prop value is changing for loading but it is not changing in the state
This is my component
import React, { Component } from "react";
import { connect } from "react-redux";
import {
getAccounts,
deleteAccounts,
addAccount,
} from "../../../actions/accountActions";
import { getUsersForTenant } from "../../../actions/userActions";
import { Drawer } from "antd";
import getSortUrl from "../../../utils/getSortUrl";
import "../tablepage.css";
import Table from "../../../components/Table/Table";
import SearchHeader from "../../../components/SearchHeader/SearchHeader";
import Loading from "../../../components/Loading/Loading";
import AddAccount from "../../../components/AddEntities/AddAccount/AddAccount";
class AllAccounts extends Component {
constructor(props) {
super(props);
this.fetchData = this.fetchData.bind(this);
this.setSort = this.setSort.bind(this);
this.deleteRows = this.deleteRows.bind(this);
this.toggleDrawer = this.toggleDrawer.bind(this);
this.addAccount = this.addAccount.bind(this);
}
state = {
page: 0,
size: 50,
loading: this.props.loading,
accounts: this.props.accounts,
sort: undefined,
selectedItems: [],
checkboxActive: false,
drawerVisible: false,
columns: [
{
key: "name",
title: "Name",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: true,
},
{
key: "companyDomain",
title: "Company Domain",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "industrySector.name",
title: "Industry Sector",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "picture",
title: "Picture",
enabled: false,
searchable: false,
type: "picture",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "nbrEmployees",
title: "No. Employees",
enabled: true,
searchable: true,
type: "number",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "fixedPhone",
title: "Phone",
enabled: true,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "source.name",
title: "Source",
enabled: false,
searchable: true,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "linkedIn",
title: "LinkedIn",
enabled: true,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "social",
title: "Social Networks",
title: "Social Networks",
enabled: true,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "twitterPage",
title: "Twitter",
title: "twitter",
enabled: false,
bindCol: "social",
bindColTitle: "Social",
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "instagramPage",
title: "Instagram",
enabled: false,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "googlePlus",
title: "Google Plus",
enabled: false,
searchable: false,
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "user",
title: "User",
enabled: false,
searchable: false,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "isCustomer",
title: "Is Customer",
enabled: false,
searchable: false,
type: "boolean",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
{
key: "Tags",
title: "Tags",
enabled: true,
searchable: false,
type: "string",
selected: false,
sortActive: false,
sortOrder: "ASC",
showCheckbox: false,
},
],
};
toggleDrawer = () => {
this.setState({
drawerVisible: !this.state.drawerVisible,
});
};
deleteRows = (rows) => {
if (rows) {
this.props.deleteAccounts(rows, 1);
this.setState({
loading: true,
});
} else {
const { selectedItems } = this.state;
this.props.deleteAccounts(selectedItems, 1);
this.setState({
selectedItems: [],
loading: true,
});
}
};
addAccount = (accountData) => {
this.props.addAccount(accountData, 1);
};
componentDidUpdate(prevState, prevProps, snap) {
// if (prevProps.accounts != this.props.accounts) {
// this.setState({
// accounts: this.props.accounts,
// loading: false,
// });
// }
// if (prevProps.users != this.props.users) {
// this.setState({
// assignableUsers: this.props.users,
// });
// }
}
setSort = (column) => {
this.setState({
sort: column,
});
};
selectRow = (select, row) => {
if (select) {
this.setState({
selectedItems: [...this.state.selectedItems, row],
checkboxActive: true,
});
} else {
var { selectedItems } = this.state;
var index = 0;
for (var i = 0; i < selectedItems.length; i++) {
if (selectedItems[i].id == row.id) {
console.log(i);
index = i;
}
}
selectedItems.splice(index, 1);
if (selectedItems.length == 0) {
this.setState({
selectedItems: selectedItems,
checkboxActive: false,
});
} else {
this.setState({
selectedItems: selectedItems,
});
}
}
};
fetchData = () => {
this.setState(
{
loading: true,
},
() => {
const { page, size, sort } = this.state;
var sortUrl = "";
if (sort) {
const sortKey = sort.key;
const sortOrder = sort.sortOrder;
sortUrl = getSortUrl(sortKey, sortOrder);
}
this.props.getAccounts(page, size, sortUrl);
}
);
};
componentDidMount() {
this.fetchData(0, 50, undefined);
this.props.getUsersForTenant();
}
toggleEnableColumn = (index) => {
const { columns } = this.state;
var enableOccured = false;
columns[index].enabled = !columns[index].enabled;
columns.forEach((col) => {
if (!enableOccured && col.enabled) {
col.showCheckbox = true;
enableOccured = true;
} else {
col.showCheckbox = false;
}
});
this.setState({
columns: columns,
});
};
render() {
const {
size,
page,
accounts,
columns,
loading,
checkboxActive,
drawerVisible,
} = this.state;
return (
<div className="table-page-container">
<Loading loading={loading} />
<Drawer
title="Add New Account"
placement="right"
closable={true}
visible={drawerVisible}
onClose={this.toggleDrawer}
>
<AddAccount
toggleDrawer={this.toggleDrawer}
assignableUsers={this.props.users}
addAccount={this.addAccount}
/>
</Drawer>
<div className="breadcrumb-container"></div>
<div className="searchbar-container">
<SearchHeader
columns={columns}
checkboxActive={checkboxActive}
fetchData={this.fetchData}
deleteData={this.deleteRows}
toggleDrawer={this.toggleDrawer}
/>
</div>
<Table
size={size}
page={page}
data={accounts}
checkboxActive={checkboxActive}
module={"accounts"}
columns={columns}
toggleEnableColumn={this.toggleEnableColumn}
className="table-container"
selectRow={this.selectRow}
fetchData={this.fetchData}
setSort={this.setSort}
deleteData={this.deleteRows}
/>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
accounts: state.account.accounts,
users: state.user.users,
loading: state.account.loading,
};
};
const mapDispatchToProps = (dispatch) => {
return {
getAccounts: (page, size, sort) => dispatch(getAccounts(page, size, sort)),
addAccount: (accountData, accountType) =>
dispatch(addAccount(accountData, accountType)),
deleteAccounts: (rows, accountType) =>
dispatch(deleteAccounts(rows, accountType)),
getUsersForTenant: () => dispatch(getUsersForTenant()),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(AllAccounts);
This is the reducer
import {
GET_ACCOUNT,
GET_ACCOUNTS,
GET_CUSTOMERS,
GET_PROSPECTS,
DELETE_ACCOUNT,
SET_ACCOUNTS_LOADING,
SET_ACCOUNTS_ERROR,
CLEAR_ERRORS,
} from "../actions/types";
const defaultState = {
accounts: [],
customers: [],
prospects: [],
loading: false,
errors: {},
};
const accountReducer = (state = defaultState, action) => {
switch (action.type) {
case GET_ACCOUNTS:
return {
...state,
accounts: action.payload,
errors: {},
};
case GET_CUSTOMERS:
return {
...state,
customers: action.payload,
errors: {},
};
case GET_PROSPECTS:
return {
...state,
prospects: action.payload,
errors: {},
};
case CLEAR_ERRORS:
return {
...state,
errors: {},
};
case SET_ACCOUNTS_LOADING:
return {
...state,
loading: action.payload,
};
case SET_ACCOUNTS_ERROR:
return {
...state,
errors: action.payload,
};
default:
return state;
}
};
export default accountReducer;
Upvotes: 1
Views: 987
Reputation: 2165
What you might need is the static getDerivedStateFromProps(props, state)
This method exists for rare use cases where the state depends on changes in props over time.
In order for your props to flow through your local state, you can write a logic inside that life-cycle method.
static getDerivedStateFromProps(props, state) {
if (!isEqual(props.accounts,state.accounts)) {
return {
accounts: props.accounts
};
}
return null;
}
}
Please take note that I am using isEqual
from lodash/isEqual
to deep check equality between state and props otherwise it will update everytime props flow in.
Reference: https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops
Upvotes: 2