When a user adds additional information, a mutation is made to the database adding the new info, then the local state is updated, adding the new information to the lead.
My mutation and state seem to get updated fine, the issue seems to be that the state of the Material Table component does not match its 'data' prop. I can see in the React Dev tools that the state was updated in the parent component and is being passes down, the table just seems to be using stale data until I manually refresh the page.
I will attach images of the React Devtools as well as some code snippets. Any help would be much appreciated.
Devtools Material Table data prop:
Devtools Material Table State
Material Table Parent Component:
const Leads = () => {
const [leadState, setLeadState] = useState({});
const [userLeadsLoaded, setUserLeadsLoaded] = React.useState(false);
const [userLeads, setUserLeads] = React.useState([]);
const { isAuthenticated, user, loading } = useAuth()
const [
createLead,
{ data,
// loading: mutationLoading,
error: mutationError },
] = useMutation(GQL_MUTATION_CREATE_LEAD);
const params = { id: isAuthenticated ? user.id : null };
const {
loading: apolloLoading,
error: apolloError,
data: apolloData,
} = useQuery(GQL_QUERY_ALL_LEADS, {
variables: params,
});
useEffect(() => {
if (apolloData) {
if (!userLeadsLoaded) {
const { leads } = apolloData;
const editable = leads.map(o => ({ ...o }));
setUserLeads(editable);
setUserLeadsLoaded(true);
};
}
}, [apolloData])
if (apolloLoading) {
return (
<>
<CircularProgress variant="indeterminate" />
</>
);
};
if (apolloError) {
console.log(apolloError)
//TODO: Do something with the error, ie default user?
return (
<div>
<div>Oh no, there was a problem. Try refreshing the app.</div>
<pre>{apolloError.message}</pre>
</div>
);
};
return (
<>
<Layout leadState={leadState} setLeads={setUserLeads} leads={userLeads} setLeadState={setLeadState} createLead={createLead}>
{apolloLoading ? (<CircularProgress variant="indeterminate" />) : (<LeadsTable leads={userLeads} setLeads={setUserLeads} />)}
</Layout>
</>
)
}
export default Leads
Handle Submit function for adding additional information:
const handleSubmit = async (event) => {
event.preventDefault();
const updatedLead = {
id: leadState.id,
first_name: leadState.firstName,
last_name: leadState.lastName,
email_one: leadState.email,
address_one: leadState.addressOne,
address_two: leadState.addressTwo,
city: leadState.city,
state_abbr: leadState.state,
zip: leadState.zipCode,
phone_cell: leadState.phone,
suffix: suffix,
address_verified: true
}
const { data } = await updateLead({
variables: updatedLead,
refetchQueries: [{ query: GQL_QUERY_GET_USERS_LEADS, variables: { id: user.id } }]
})
const newLeads = updateIndexById(leads, data.updateLead)
console.log('New leads before setLeads: ', newLeads)
setLeads(newLeads)
// setSelectedRow(data.updateLead)
handleClose()
};
Material Table Component:
const columnDetails = [
{ title: 'First Name', field: 'first_name' },
{ title: 'Last Name', field: 'last_name' },
{ title: 'Phone Cell', field: 'phone_cell' },
{ title: 'Email', field: 'email_one' },
{ title: 'Stage', field: 'stage', lookup: { New: 'New', Working: 'Working', Converted: 'Converted' } },
{ title: 'Active', field: 'active', lookup: { Active: 'Active' } },
];
const LeadsTable = ({ leads, setLeads }) => {
const classes = useStyles();
const { user } = useAuth();
const [isLeadDrawerOpen, setIsLeadDrawerOpen] = React.useState(false);
const [selectedRow, setSelectedRow] = React.useState({});
const columns = React.useMemo(() => columnDetails);
const handleClose = () => {
setIsLeadDrawerOpen(!isLeadDrawerOpen);
}
console.log('All leads from leads table render: ', leads)
return (
<>
<MaterialTable
title='Leads'
columns={columns}
data={leads}
icons={tableIcons}
options={{
exportButton: false,
hover: true,
pageSize: 10,
pageSizeOptions: [10, 20, 30, 50, 100],
}}
onRowClick={(event, row) => {
console.log('Selected Row:', row)
setSelectedRow(row);
setIsLeadDrawerOpen(true);
}}
style={{
padding: 20,
}}
/>
<Drawer
variant="temporary"
open={isLeadDrawerOpen}
anchor="right"
onClose={handleClose}
className={classes.drawer}
>
<LeadDrawer onCancel={handleClose} lead={selectedRow} setLeads={setLeads} setSelectedRow={setSelectedRow} leads={leads} />
</Drawer>
</>
);
};
export default LeadsTable;
Try creating an object that contains refetchQueries and awaitRefetchQueries: true. Pass that object to useMutation hook as a 2nd parameter. See example below:
const [
createLead,
{ data,
loading: mutationLoading,
error: mutationError },
] = useMutation(GQL_MUTATION_CREATE_LEAD, {
refetchQueries: [{ query: GQL_QUERY_GET_USERS_LEADS, variables: { id: user.id } }],
awaitRefetchQueries: true,
});
Manually updating cache. Example blow is adding a new todo. In your case you can find and update the record before writing the query.
const updateCache = (cache, {data}) => {
// Fetch the todos from the cache
const existingTodos = cache.readQuery({
query: GET_MY_TODOS
});
// Add the new todo to the cache (or find and update an existing record here)
const newTodo = data.insert_todos.returning[0];
cache.writeQuery({
query: GET_MY_TODOS,
data: {todos: [newTodo, ...existingTodos.todos]}
});
};
const [addTodo] = useMutation(ADD_TODO, {update: updateCache});
Related
Thanks all in advance.
Going by the screenshot:
enter image description here
I wish to use a dynamic variable (filter) in line 33 but it keeps throwing error. If I use the name properties of the object, Filter_M (eg: "ALL", it works fine. If I use the the values too by using the functions (eg:
(order) => !order.completed
) directly, it works fine.
How can I resolve this?
Note: I am following similar procedure as used in MDN article. See:
Back to the Filter Buttons
A portion of my code is shown below while links to react components are shown at the bottom:
import React from "react";
import FilterButton from "./components/filterButton";
import MyOrder from "./components/MyOrder";
// const ORDER = [
// { cname: 'ki', item: 'liveChicken', quantity: 0, id: "order-0", completed: true },
// { cname: 'fu', item: 'egg', quantity: 0, id: "order-1", completed: false },
// { cname: 'nu', item: 'chicken', quantity: 0, id: "order-2", completed: false}
// ]
// const root = ReactDOM.createRoot(document.getElementById('root'));
// root.render(
// <React.StrictMode>
// <App2 orders={ORDER} />
// </React.StrictMode>
// );
const FILTER_M = {
ALL: () => true,
Active: (order) => !order.completed,
Completed: (order) => order.completed
};
const FILTER_NAMES = Object.keys(FILTER_M);
function App(props) {
const chickenPrice = 5000;
const [filter, setFilter] = useState('All');
const [orders, setOrders] = useState(props.orders)
const orderList = orders
.filter(FILTER_M[filter])
.map((order) => (
<MyOrder
item={order.item}
quantity={order.quantity}
cname={order.cname}
id={order.id}
completed={order.completed}
key={order.id}
/>))
const filterList = FILTER_NAMES.map((cname) => (
<FilterButton
key={cname}
cname={cname}
isPressed={cname === filter}
setFilter={setFilter}
/>
));
}
Code Sandbox
I am expecting to display dynamically, the tasks/orders either active, completed, with all orders shown by default.
I have tried hard-coding it by using the property name or the values and it all worked out fine. But using the named variable in object (FILTER_MAP) bracket notation which is the only way of accessing named variable as name property of an object.
Based on the MDN article you provided this code should work, I can't see the complete picture of your code but anyway this code below is working :
const DATA = [
{ id: 'todo-0', name: 'Eat', completed: true },
{ id: 'todo-1', name: 'Sleep', completed: false },
{ id: 'todo-2', name: 'Repeat', completed: false },
];
const filterBy= {
All: (order) => true,
Active: (order) => !order.completed,
Completed: (order) => order.completed,
};
const DisplayList = () => {
const [filter, setFilter] = useState('All');
const [orders, setOrders] = useState(DATA);
console.log(filterBy[filter]);
const orderList = orders.filter(filterBy[filter]).map(order => (
<li key={order.id} id={order.id}>
<p>{order.name}</p>
<p>{`${order.completed}`}</p>
</li>
));
return (
<>
<button onClick={() => setFilter('Active')}>
view active orders ⬇
</button>
{orderList}
</>
);
};
export default function App() {
return (
<DisplayList />
);
}
a working sample in code sandbox
The problem is here :
const FILTER_MAP = {
ALL: () => true, // HERE (ALL) is all CAPS
Active: (order) => !order.completed,
Completed: (order) => order.completed
};
and your are trying to access (All) a property that doesn't exist in FILTER_MAP
const [filter, setFilter] = useState('All'); // not the same as (ALL) in FILTER_MAP
and that is a good example of why you should use type script, because TS would have helped you find this typo.
I have a new app I'm working on that has a lot of CRUD functionality. A list/grid and then a modal with multiple tabs of content and a save button in the modal header. I'm wondering about patterns to separate state logic from the JSX component so it's easier to read/maintain.
I read about "lifting state", but that makes this item component unruly with the callbacks (and it'll get worse for sure as more detail is added). Is it possible to put the handlers and the state itself in a custom hook and then pull them in where needed, instead of having it at "the closest common ancestor"? For example,
const {company, setCompany, updateCompany, getCompanyByCode, createCompany, onNameChangeHandler, onTitleChangeHandler, etc.} from "./useCompany"
Would all users of this hook have the same view of the data and be able to see and effect updates? I've read about putting data fetching logic in hooks, but what about change handlers for what could be 20 or more fields? I think it's the clutter of the callbacks that bothers me the most.
Here is a shortened version of a component that renders the tabs and data for a specific domain item. Is this a use case for context and/or custom hooks?
import {
getCompanyByCode,
updateCompany,
createCompany,
companyImageUpload,
} from "../../api/companyApi";
const initialState: CompanyItemDetailModel = {
code: "",
name: { en: "", es: "" },
title: { en: "", es: "" },
description: { en: "", es: "" },
displayOrder: 0,
enabled: false,
};
export interface CompanyItemProps {
onDetailsDialogCloseHandler: DetailsCancelHandler;
companyCode: string;
onSaveHandler: () => void;
}
const CompanyItem = (props: CompanyItemProps) => {
const { CompanyCode, onDetailsDialogCloseHandler, onSaveHandler } = props;
const classes = useStyles();
const [tabValue, setTabValue] = useState<Number>(0);
const [isLoading, setIsLoading] = useState(true);
const nameRef = useRef({ en: "", es: "" });
const [Company, setCompany] = useState<CompanyItemDetailModel>(initialState);
const [saveGraphics, setSaveGraphics] = useState(false);
useEffect(() => {
async function getCompany(code: string) {
try {
const payload = await getCompanyByCode(code);
nameRef.current.en = payload.name.en;
setCompany(payload);
} catch (e) {
console.log(e);
} finally {
setIsLoading(false);
}
}
if (CompanyCode.length > 0) {
getCompany(CompanyCode);
}
}, [CompanyCode]);
function handleTabChange(e: React.ChangeEvent<{}>, newValue: number) {
setTabValue(newValue);
}
function detailsDialogSaveHandler() {
const CompanyToSave = {
...Company,
name: JSON.stringify({ ...Company.name }),
description: JSON.stringify({ ...Company.description }),
title: JSON.stringify({ ...Company.title }),
};
if (CompanyCode.length > 0) {
updateCompany(CompanyToSave as any).then((e) => handleSaveComplete());
} else {
createCompany(CompanyToSave as any).then((e) => handleSaveComplete());
}
setSaveGraphics(true);
}
function handleSaveComplete() {
onSaveHandler();
}
function detailsDialogCloseHandler(e: React.MouseEvent) {
onDetailsDialogCloseHandler(e);
}
function handleNameTextChange(e: React.ChangeEvent<HTMLInputElement>) {
setCompany((prevState) => ({
...prevState,
name: {
...prevState.name,
en: e.target.value,
},
}));
}
function handleCompanyCodeTextChange(e: React.ChangeEvent<HTMLInputElement>) {
setCompany((prevState) => ({
...prevState,
code: e.target.value,
}));
}
function handleEnabledCheckboxChange(e: React.ChangeEvent<HTMLInputElement>) {
setCompany((prevState) => ({
...prevState,
enabled: e.target.checked,
}));
}
function handleTitleTextChange(e: React.ChangeEvent<HTMLInputElement>) {
setCompany((prevState) => ({
...prevState,
title: {
...prevState.title,
en: e.target.value,
},
}));
}
return (
<DetailsDialog>
<div className={classes.root}>
<Form>
<ModalHeader
name={nameRef.current}
languageCode={"en"}
onTabChange={handleTabChange}
onCancelHandler={detailsDialogCloseHandler}
onSaveHandler={detailsDialogSaveHandler}
tabTypes={[
DetailsTabTypes.Details,
DetailsTabTypes.Images,
]}
/>
<TabPanel value={tabValue} index={0} dialog={true}>
<CompanyDetailsTab
details={Company}
isEditMode={CompanyCode.length > 1}
languageCode={"en"}
handleNameTextChange={handleNameTextChange}
handleCompanyCodeTextChange={handleCompanyCodeTextChange}
handleEnabledCheckboxChange={handleEnabledCheckboxChange}
handleTitleTextChange={handleTitleTextChange}
handleDescriptionTextChange={handleDescriptionTextChange}
/>
</TabPanel>
<TabPanel value={tabValue} index={1} dialog={true}>
<ImageList />
</TabPanel>
</Form>
</div>
</DetailsDialog>
);
};
export default CompanyItem;
So in my database there are incoming calls, outgoing calls, meetings and emails. In this component, I want to get all of them and combine them into one array to fill my datatable and create a "latest activity" table. I have fetched each type from my redux store and have a useEffect for each to append it to the data that fills the datatable. It all works fine and I get the result I want however the error in the title appears and turns my page into a vegetable afterwards.
const [incomingCalls, setIncomingCalls] = useState([])
const [outgoingCalls, setOutgoingCalls] = useState([])
const [meetings, setMeetings] = useState([])
const [emails, setEmails] = useState([])
const [showIncoming, setShowIncoming] = useState(false);
const [showId, setShowId] = useState('')
const [data, setData] = useState([...incomingCalls])
const incomingCallList = useSelector((state) => state.incomingCallList);
const {
loading: loadingCalls,
error: errorIncCalls,
incomingCalls: incCalls,
} = incomingCallList;
const outgoingCallList = useSelector((state) => state.outgoingCallList);
const {
loading: loadingOutCalls,
error: errorOutCalls,
outgoingCalls: outCalls,
} = outgoingCallList;
const meetingList = useSelector((state) => state.meetingList);
const {
loading: loadingMeetings,
error: errorMeetings,
meetings: meetings_list,
} = meetingList;
const emailList = useSelector((state) => state.emailList);
const {
loading: loadingEmails,
error: errorEmails,
emails: email_list,
} = emailList;
useEffect(() => {
if(props.contractor._id) {
dispatch(listIncomingCalls())
dispatch(listOutgoingCalls())
dispatch(listMeetings())
dispatch(listEmails())
}
}, [props.contractor._id, dispatch])
const showIncomingModalHandler = id => {
console.log(id)
}
useEffect(() => {
if(incCalls) {
const transformedIncomingCalls = incCalls.filter(call => call.contractor._id === props.contractor._id).map(c => ({
type: 'Incoming Call',
contact_person: c.contact_person,
logged_by: c.created_by.name,
date: c.time_created,
link: <Button onClick={() => showIncomingModalHandler(c._id)}><Eye /></Button>
}))
setIncomingCalls(transformedIncomingCalls)
setData([...incomingCalls])
}
}, [incCalls, incomingCalls, props.contractor._id])
useEffect(() => {
if(outCalls) {
const transformedOutgoingCalls = outCalls.filter(call => call.contractor._id === props.contractor._id).map(c => ({
type: 'Outgoing Call',
contact_person: c.contact_person,
logged_by: c.created_by.name,
date: c.time_created,
link: <> <LinkContainer to={`/outgoing-calls/${c._id}`} className='text-success' style={{ cursor: 'pointer'}}><Eye /></LinkContainer> </>
}))
setOutgoingCalls(transformedOutgoingCalls)
setData([...incomingCalls, ...outgoingCalls])
}
}, [outCalls, incomingCalls, outgoingCalls, props.contractor._id])
useEffect(() => {
if(meetings_list) {
const transformedMeetings = meetings_list.filter(meeting => meeting.contractor._id === props.contractor._id).map(m => ({
type: 'Meeting',
contact_person: m.held_with,
logged_by: m.logged_by.name,
date: m.meeting_time,
link: <> <LinkContainer to={`/meeting/${m._id}`} className='text-success' style={{ cursor: 'pointer'}}><Eye /></LinkContainer> </>
}))
setMeetings(transformedMeetings)
setData([...incomingCalls, ...outgoingCalls, ...meetings])
}
}, [meetings_list, incomingCalls, outgoingCalls, meetings, props.contractor._id])
useEffect(() => {
if(email_list) {
const transformedEmails = email_list.filter(email => email.contractor._id === props.contractor._id).map(e => ({
type: 'Email',
contact_person: e.contact_person,
logged_by: e.logged_by.name,
date: e.date,
link: <> <LinkContainer to={`/emails/${e.contractor._id}/`} className='text-success' style={{ cursor: 'pointer'}}><Eye /></LinkContainer> </>
}))
setEmails(transformedEmails)
setData([...incomingCalls, ...outgoingCalls, ...meetings, ...emails])
}
}, [email_list, incomingCalls, outgoingCalls, meetings, emails, props.contractor._id])
const columns = [
{ name: 'Action', selector: 'link', sortable: true },
{ name: 'Activity Type', selector: 'type', sortable: true },
{ name: 'Contact Person', selector: 'contact_person', sortable: true },
{ name: 'Logged By', selector: 'logged_by', sortable: true },
{ name: 'Date', selector: 'date', sortable: true }
]
The values which you try to pass in the dependency array of react has to be primitive . It should not be array or object.
For example, consider this useEffect
useEffect(() => {
if(incCalls) {
const transformedIncomingCalls = incCalls.filter(call => call.contractor._id === props.contractor._id).map(c => ({
type: 'Incoming Call',
contact_person: c.contact_person,
logged_by: c.created_by.name,
date: c.time_created,
link: <Button onClick={() => showIncomingModalHandler(c._id)}><Eye /></Button>
}))
setIncomingCalls(transformedIncomingCalls)
setData([...incomingCalls])
}
}, [incCalls, incomingCalls, props.contractor._id])
when this useEffect runs you are setting the state with
setIncomingCalls(transformedIncomingCalls)
setData([...incomingCalls])
Once there is state update your entire function will re-run. Now in your code you have this
const {
loading: loadingCalls,
error: errorIncCalls,
incomingCalls: incCalls,
} = incomingCallList;
Now for every re-render you are creating a new incCalls which is array. So when you are passing a dependency as an array react does shallow comparison. It checks whether the previous reference of this array is same as the new one ? . But here it is not because the reference changes each time for every re-render . So your useEffect will run again and this leads to infinite re-render and the maximum stack exceeded error.
Avoid passing arrays or objects as a dependency in the array. You can modify your dependency array as below . This will trigger the useEffect only when the length of inCalls or incoming is changed
[incCalls.length, incomingCalls.length, props.contractor._id]
I have an array set in state like:
const Theme = {
name: "theme",
roots: {
theme: Theme,
},
state: {
theme: {
quiz: {
quizGender: null,
quizSleepComfort: {
justMe: {
soft: null,
medium: null,
firm: null,
},
partner: {
soft: null,
medium: null,
firm: null,
}
},
},
},
},
actions: {
// ...
},
};
I then have a component that has checkboxes, one for soft, medium, and firm. The code for the component is:
const Question = ({ state }) => {
const [checkedItems, setCheckedItems] = useState([]);
const checkboxes = [
{
label: "Firm",
value: "firm",
},
{
label: "Medium",
value: "medium",
},
{
label: "Soft",
value: "soft",
},
];
state.theme.quiz.quizSleepComfort.justMe = checkedItems;
return (
<QuestionCommonContainer>
{checkboxes.map((item, id) => (
<QuizCheckbox
label={item.label}
name={item.label}
value={item.value}
selected={checkedItems[item.value] === true}
onChange={(e) => {
setCheckedItems({
...checkedItems,
[e.target.value]: e.target.checked,
});
}}
/>
))}
</QuestionCommonContainer>
);
};
export default connect(Question);
This specific component is just interacting with state.theme.quiz.quizSleepComfort.justMe object, not the partner object.
As of right now when a checkbox is selected, let's say the checkbox for "firm" is checked, the state gets updated to what looks like this:
...
quizSleepComfort: {
justMe: {
firm: true,
},
partner: {
soft: null,
medium: null,
firm: null,
}
},
...
I am trying to figure out how I would be able to alter this components code so that instead of setting the justMe object to include only the items that are checked (in this case "firm"), it should keep the other items as well ("soft", "medium") as null.
Please let me know if there is more info i should provide.
Okay. So the following is bad practice
state.theme.quiz.quizSleepComfort.justMe = checkedItems;
You should pass a function to the Question component, something like onChange.
The onChange function should update the state in your parent component. Use the spread operator ... to get a copy of the old object. for example
const onChange = (newState) =>
setState((oldState) => ({
...oldState,
justMe: { ...oldState.justMe, ...newState },
}));
the resulting object will contain all the properties of the original state but will overwrite any property set on newState in justMe. If the property that you want to update is more nested, just repeat the steps of spreading.
--- UPDATE ---
I have added an example that I think is close to what you are trying to achieve.
const Parent = () => {
const [state, setState] = useState(initialState);
const onChange = useCallback(
(newState) =>
setState((oldState) => ({
...oldState,
theme: {
...oldState.theme,
quiz: {
...oldState.theme.quiz,
quizSleepComfort: {
...oldState.theme.quizSleepComfort,
justMe: {
...oldState.theme.quizSleepComfort.justMe,
...newState,
},,
},
},
},
})),
[],
);
return <Question onChange={onChange} />;
};
const checkboxes = [
{
label: 'Firm',
value: 'firm',
},
{
label: 'Medium',
value: 'medium',
},
{
label: 'Soft',
value: 'soft',
},
];
const Question = ({ onChange }) => {
const [checkedItems, setCheckedItems] = useState([]);
useEffect(() => {
onChange(checkedItems);
}, [checkedItems, onChange]);
return (
<QuestionCommonContainer>
{checkboxes.map((item, id) => (
<QuizCheckbox
label={item.label}
name={item.label}
value={item.value}
selected={checkedItems[item.value] === true}
onChange={(e) => {
setCheckedItems((oldCheckedItems) => ({
...oldCheckedItems,
[e.target.value]: e.target.checked,
}));
}}
/>
))}
</QuestionCommonContainer>
);
};
export default connect(Question);
As you are having a really nested object to update, it might be worth taking a look at Object.assign
I am making a App in Reactjs. In it I have an API that gets data from a AWS database table and populates a state array which then populates a tables.
I cant figure out how to let a user in turn update the values of the table and then save those changes and let the API upload it back into the data base.
I have a update method but it gives an error saying that I cant update the state Array or would complain that the column array is undefined.
I have the following code:
export default function Complaints(props) {
const [complaint, setComplaint] = useState([]);
const [isLoading, setIsLoading] = useState(true);
const [isInEditMode, setIsEditMode] = useState(false);
const [defaultValue, setDefaultValue] = useState("");
var columsArr = [
{ title: 'Customer ID', field: 'id' },
{ title: 'Issue', field: 'complaintName' },
{ title: 'Description', field: 'complaintDescription'},
{ title: 'Order ID', field: 'complaintOrderId'},
{ title: 'Submitted', field: 'createdAt'},
{ title: 'Updated', field: 'updatedAt'},
{ title: 'Admin Comment', field: 'adminComment'},
];
useEffect(() => {
async function onLoad() {
if (!props.isAuthenticated) {
return;
}
try {
const complaint = await loadComplaint();
setComplaint(complaint);
setState({
columns: [state.columns, ...columsArr],
complaint: [...state.complaint, ...complaint]
});
console.log(complaint)
} catch (e) {
alert(e);
}
setIsLoading(false);
}
onLoad();
}, [props.isAuthenticated]);
function loadComplaint() {
return API.get("kleen", "/Complaint");
}
// function edit(adminComment) {
// setIsEditMode(true);
// setDefaultValue(adminComment);
// console.log("value is"+ adminComment);
// }
// function updateComplaint() {
// return API.put("kleen", `/Complaint/${props.}`);
// }
const [state, setState] = React.useState({
columns: [],
complaint: []
});
return (
<MaterialTable style={{
marginTop: "8rem",
marginLeft: "auto",
marginRight: "auto",
position: "sticky",
}}
title="Complaints"
columns={state.columns}
data={state.complaint}
editable={{
onRowUpdate: (newData, oldData) =>
new Promise(resolve => {
setTimeout(() => {
resolve();
if (oldData) {
let key = 1;
setState(prevState => {
complaint: prevState.complaint.map(el => el.key === key ? {...el, adminComment: "testing"}: el)
// const data = [...prevState.data];
// data[data.indexOf(oldData)] = newData;
// return { ...prevState, data };
});
}
}, 600);
}),
}}
/>
);
}
I am very new to Reactjs, any help would be greatly appreciated.
One way that you can achieve is by:
First store the state in a variable
Update the array variable
Restore the variable to the state.
If you want to use state then better to use component class
export default class Complaints extends Component {
//assign initial value to state
state={
propsObj : this.props
}
...
}
If you want to use component you have to import it
import React, { Component } from "react";
inside component class you have to use this.props instead of props
later if you want to change state just use this.setState({ propsObj: 'some thing new'});