Can not update the list of items? - javascript

My list of items is not being updated when I do a delete of a row even though the console.log(data) results in one less item after deleting the row, but the console.log('list of items after: ', listOfitems) gives me all full items even those that are deleted.
const [listOfitems, setListOfitems] = useState([]);
useEffect(() => {
getListOfitems();
}, [])
Please let me know what could be possibly wrong here:
editable={{
onRowDelete: (oldData) =>
new Promise((resolve, reject) => {
setTimeout(() => {
{
console.log('list of items before: ', listOfitems)
console.log('oldData.item_key;: ', oldData.item_key)
const indexToDelete = oldData.item_key;
console.log(indexToDelete)
const data =
listOfitems.filter(
(item) => ((item.item_key !== oldData.item_key))
)
setListOfitems(data);
console.log(data)
console.log(setListOfitems(data))
deleteitem(oldData);
setListOfitems(data);
console.log('list of items after: ', listOfitems)
}
resolve();
}, 1000);
}),
}}

The second argument in the useEffect hook is an array of values that the hook depends on. In your example you passed an empty array, which is great for making the hook work like ComponentDidMount(). However, since your hook now depends on no values, it will never fire again. In the below example, passing listOfItems into that array will cause the hook to fire whenever that piece of state changes. Not seeing the rest of your code, but based on your description of the problem, this is my best guess as to a solution for you.
Hope this helps.
const [listOfitems, setListOfitems] = useState([]);
useEffect(() => {
console.log('useEffect')
getListOfitems().then((listOfitems) => {
setListOfitems(listOfitems);
});
getDocuments();
}, [listOfItems]);

Every time the component is rendered a new const state is assigned to useState hook. In you case every time your component is rerendred this line runs assigning a new value to the listOfitems.
const [listOfitems, setListOfitems] = useState([]);
This means that console logging out the state before the component rerenders would return the old state.
Console.log(data) results in the correct state because you simply filter and return a new array.
As dvfleet413 mentioned you do not include the listOfItems in the argument array of the useEffect meaning that your component only renders once.

The set* methods for state are asynchronous, so if you try to access listOfitems immediately after calling setListOfitems, you could be using the old value and not the newly updated one.
You could use a separate useEffect method that is dependent on the value being set in the first one (use the second param like [listOfitems]). This other method should get triggered after the update.
In short - the data IS being updated, but your console.log is displaying the old value before the update is complete.
edit: Code example:
useEffect(()=>{
getListOfitems()
// console.log here may NOT show the new listOfitems value because
// setListOfitems is asynchronous, and getListOfitems may also be
}, []) // only loads on the initial mount
I assume getListOfitems will retrieve the data from an external source initially, and calls setListOfitems inside it. The code in the post does not show what is happening.
A second useEffect could look like:
useEffect(()=>{
// do something with listOfitems
}, [listOfitems]) // gets called every time listOfitems is updated

Related

how to map array result from console.log into table in react js

I have an array of results coming from an API that I called using axios. get(). Then the result is in array and I want to map it into table in react js.
Below is the API fetching data
const [data, getData] = useState([])
useEffect(() => {
axios.get("http://localhost:4000/api/authentication/history")
.then(result =>{
console.log(result.data.result)
getData(JSON.stringify(result.data.result))
console.log(data.length)
})
}, [])
The line console.log(data.length) returns 0. I dont know why the data is not stored in the data function. That is why when I map {data.map} into it will return error as data.map is not a function. So, is there a simpler way to display and map this array of result into react js table?
Here is the image of the array of result (it is not in json type but in array)
Update #1
Since posting this (7 hours ago), I tried to do this myself, and realised I completely invented this feature, and callback isn't actually a function of useState
I did some research and came across this very useful function:
const useStateCallback = (initialState) => {
const [state, setState] = useState(initialState);
const cbRef = useRef(null); // init mutable ref container for callbacks
const setStateCallback = useCallback((s, cb) => {
cbRef.current = cb; // store current, passed callback in ref
setState(s);
}, []); // keep object reference stable, exactly like `useState`
useEffect(() => {
// cb.current is `null` on initial render,
// so we only invoke callback on state *updates*
if (cbRef.current) {
cbRef.current(state);
cbRef.current = null; // reset callback after execution
}
}, [state]);
return [state, setStateCallback];
};
Original
I don't know what getData is, but I'll assume it's state, and you have something like this:
const [data, getData] = useStateCallback(); // previously useState
If that's the case, when you call your getData, you can do a callback as the 2nd argument. That callback happens when your state updates successfully:
...
getData(JSON.stringify(result.data.result), () => console.log(data.length));
...
If that's now how you're doing it, then I'd suggest you change whatever you're doing to be in state, and also rename getData to setData
Explanation
When you're calling your getData, you're telling react that you want to update your data? Great! The thing to note is, react doesn't do this update immediately. Instead, it updates it (and other state) in the future, all at the same time.
With that in mind, you pass the callback function as the 2nd argument to tell react what you want to happen once this specific state has been updated
As for getData to setData? That's because the function doesn't return (get) anything, but does set something. Makes your code clearer

React useState doesn't update even with useEffect added

Probably it is a classic issue with useState which is not updating.
So there is a tree with some checkboxes, some of them are already checked as they map some data from an endpoint.
The user has the possibility to check/uncheck them. There is a "cancel" button that should reset them to the original form.
Here is the code:
const [originalValues, setOriginalValues] = useState<string[]>([]);
...
const handleCancel = () => {
const originalValues = myData || []; //myData is the original data stored in a const
setOriginalValues(() => [...myData]);
};
...
useEffect(() => {
setOriginalValues(originalValues);
}, [originalValues]);
However, it is not working, the tree is not updating as it should. Is it something wrong here?
Just do the following, no need for ()=> the state will update inside the hook if called, plus change the constant it will cause confusion inside your code and protentional name clash later on, with the current state variable name, and also make sure your data are there and you are not injection empty array !!!! which could be the case as well !.
// Make sure data are available
console.log(myData)
// Then change the state
setOriginalValues([...myData]);

Array doesn't update after adding new item, using React Hooks

I have an array that shows a set of items attached to a user. The array checks it first if the current user is on the item's inventory and then displayed as 'user name' and 'date borrowed' on a table. The adding feature is done in a modal, and suppose to update the table.
The problem is everytime I add, delete or update, the table doesn't update at all. Also this table is an expandend component of another table (react-data-table-component)
Here is the useState, and useEffect of my table:
const InventoryTable= ({
selectedUser,
items,
getItems,
getUsers
}) => {
useEffect(() => {
getItems();
getUsers();
}, []);
const [data, setData] = useState([]);
useEffect(() => {
let data= [];
data= items?.filter((item) =>
item?.users.some(
(user) => parseInt(user?.id) === parseInt(selectedUser?._id)
)
);
setData(data);
}, []);
Note: selectedUser, is the user from the main table that was selected and this current table is to show the itms attached to it.
If I add data on the setData(data); }, []); it crashes.
Adding data, selectedUser, and items on the dependency arrays loads it non-stop that causes to crash the page
useEffect method takes 2 parameters as input.
callback
dependency
If the dependency is empty array it will be called in the similar way as Class Component with componentDidMount and componentWillUnmount lifecycle methods.
if dependency is present then the callback will be called after the UI in painted.
So clearly you have missed required dependency
I'm not sure that i understand the whole concepts of your code because it is just a small part of the code. But useEffect() will run accordingly if you want it to run as ComponenentDidMount you will use the code that you said above however in your case you want to update delete add it means you want to detect the change in data so you need to include data within the brackets like this
`useEffect(() => {
let data= [];
data= items?.filter((item) =>
item?.users.some(
(user) => parseInt(user?.id) === parseInt(selectedUser?._id)
)
);
setData(data);
}, [data,items,selectedUser]);`
Seems you forgot to pass items and selectedUser to effect dependency array.
Maybe I am wrong, but have you tried renaming data property inside useEffect? It should have problem, that you are setting state without set callback.
Try also set useState default value to [] instead of {} (object).

React Hooks: Adding new fields to an Object state does not get reflected immediately

I am using React Hooks to manage states within a component.
const addNode = () => {
let pform = pForm
let handles = [vForm, yForm, hForm]
let access_info = [virtualForm, management1Form, management2Form, consoleForm]
let newObj = {
...currentForm,
p: pform,
handles: handles,
access_info: access_info,
}
console.log('newObj', newObj)
setCurrentForm(
newRouterObj
)
console.log(currentForm)
let currArr = [...addedNodes]
currArr.push(currentForm)
setAddedNodes(currArr)
intializeForms()
}
The function above is an onClick that I use when I press an Add button. The forms (pForm, vForm, yForm, etc.) are all separate states. I gather them together and put them into a single object newObj and use setCurrentForm to update the currentForm state to newObj.
When I console.log the newObj, everything goes in fine. However, when I check the currentForm after the setCurrentForm, the fields (p, handles, and access_info) are empty.
I know that states in React can have a delay in updates so I might have to use useEffect. However, in my use case, which is to gather different states and put them in as a new field in the currentForm state seems useEffect is not the best way to solve it. Can anyone help please?
You are misunderstanding exactly how useState works. When you call the useState setter function, the state value isn't actually updated immediately, instead it will trigger the component to re-render with the updated value. Even though you call the setter half way through the function, the state value will remain the original value for the entire lifetime of that function call.
You could slightly tweak what you have to be
const addNode = () => {
...
let currArr = [...addedNodes]
// you know that currentForm is supposed to be newObj, so just push that
// see my explanation above to understand why it currentForm isn't what you expect
currArr.push(newObj)
...
}
It's an async action so values will not be assigned/updated instantly. You need to watch for the changes using useEffect hook to log new values and to do anything in case
useEffect(() => {
// Whenever `currentForm` will be updated, this callback will be invoked
console.log('updated currentForm values', currentForm);
},[currentForm]);

React Native: Strange Issue With Updating State

I am using the code below:
makeRemoteRequest = () => {
let items = [];
models.forEach(element => { //models is an array of the list of models
this.pushReports(element, items);
});
console.log("This is the item array: ",items);
this.setState({
data:items
});
console.log("This is the data in state: ",this.state.data);
}
Somehow, the console log for the items array is showing me the array that I need, but the console log for the this.state.data is empty. How can this be possible? The log for the items array is run right before state is set.
This is preventing me from updating my state.
this.setState is rendering asynchronously. And you're trying to print in next line so it will not give immediate results as you want.
Solution: do this in next line,
setTimeout(() => {console.log("This is the data in state: ",this.state.data) }, 1000)
this.setState() does not run synchronously. Your state is not guaranteed to be updated on the next immediate line, but it will be updated properly on the next render cycle. Try putting console.log within render() and you'll see.
Discussion about this topic here: https://github.com/facebook/react/issues/11527#issuecomment-360199710
Since setState works in an asynchronous way. That means after calling setState the this.state is not immediately changed. So if you want to perform an action immediately after setting state, use 2nd argument as callback on setState. Consider this example:
this.setState({
data: newData
}, () => {
//TODO: Do something with this.state here
});

Categories

Resources