Updating the useState values automatically in react js? - javascript

I have a usestate array object called mo, which gets the data from an rest api from get request. I use useEffect for getting the data.
const [mo, UpdateMO] = useState([{}]);
I will be creating an item by post request and that newly created item is stored in tempArray. This newly created item is appended to the mo array object.
UpdateMO([...mo], tempArray);
I show all the values of mo in a table. It is getting updated only once a re-render or refresh is taking place. On refreshing I would be going back to the homepage. So, how can I refresh or re-render the mo so that on creating a new item it automatically re-renders the mo.

Setting state will be done asynchronously. When you want to update state, you can grab the previous values in the state to combine with the new values.
Setting state also triggers a re-render.
// initialize state with an empty array
const [mo, setMo] = useState([]);
// get newValues and update state
setMo((previousValues) => [...previousValues, newValues]);

Use redux for that to maintain data and update data

Related

Update the cache and trigger a re-render in Apollo

I'm trying to update the cache of a certain item but changes aren't being reflected on to the ui , I have an item which is being fetched by a query that has a lot of variables and I have no access to them on the component that I'm updating that Item on and that Item is also part of a paginated list , so my code was
update = (cache)=>{
cache.data.data['ItemType_'+itemId].title = "New title"
}
as far as I know this code should update the cache of that item but it doesn't show it in the ui , is there a way to update a single item in the cache and have the result rendered ?
Directly updating the cache doesn't cause a re-render afaik. I recommend running a query with fetchPolicy: "cache-only" after you update the cache. That will update the component's data and cause a re-render without hitting the network.
Try and also make sure you are returning the correct data from the mutation.
Return the correct fields from the mutation. The required field can be id. If it is not returned from the mutation, then there will be no refresh or re-render.

React: Mapping a component with local storage data

I'm currently creating a history list component for a form in a react app and am having some trouble with the local storage.
Essentially, I want the app to render a list of past inputs from the user's local storage data. My current idea is based in duplicating the local storage data is a state variable.
const [history, setHistory] = useState([]);
On form submit I call this function with the form input as the parameter (the input is a single string)
const setLocalStorage = (input) => {
const hist = JSON.parse(localStorage.getItem('history')) || [];
console.log(hist)
hist.push(input)
localStorage.setItem('history', JSON.stringify(hist))
setHistory(hist);
}
This is meant to put the history from local story into hist, push the input that was just submitted into the existing array hist, and update the local storage with the new value. The state variable should then be updated with the most updated array of strings with the setHistory(hist) call.
Also, I want local storage to be pulled on first render so I can use that data to render the history list on initial load. I have a useEffect hook for this as shown:
useEffect(() => {
setHistory(JSON.parse(localStorage.getItem('history')))
console.log(history)
}, []);
The problem I'm facing is that the state never seems to get updated? I can instead do a console log for JSON.parse(localStorage.getItem('history')) and get the local storage array returned but this of course isn't helpful for data usage. I know that the local storage is properly being pulled from this but I'm unable to update the state for some reason. I need the state updated so I can conditionally render and use the array for mapping each item on the history list. When I console log "history" I get an empty array.
TL;DR
Concisely, what is the cleanest method to have local storage and state values maintain equivalency? Hope my post was clear enough to understand!
I'm remaking and updating a regular JS app on React for practice so I'm able to provide a live link of how I want this simple component to work.
https://giovannimalcolm.github.io/weather-dashboard/
The second returned parameter of useState is similar to the this.setState which is asynchronous. You may see that state is not changed even setHistory is called. Passing function instead of the value will avoid this issue as it will be executed after the state is updated. This might be useful for better understanding Passing function to setState()
useEffect(() => {
const hist = JSON.parse(localStorage.getItem('history'))
setHistory(prevHistory => [...prevHistory, ...hist])
}, []);

React - UseEffect hook with Redux store in dependency array and which updates the state ends in an endless loop

I have an array of certain objects in my redux store and I retrieve it like so:
const storeExpenses = useSelector(({ expenses }: RootState) => expenses.items));
I then save those expense objects also in the components local state since I have to further filter them without wanting to change them in the store.
const [expenses, setExpensesInState] = useState<Expense[]>(storeExpenses);
Now, when my store expenses are updated somewhere else, I want to refresh the local state as well, like so:
useEffect(() => {
setExpensesInState(storeExpenses));
}, [storeExpenses]);
However this results in an endless loop of the useEffect hook.
My assumption is that when I use setExpensesInState, I trigger a redraw of the component which then sets the expensesInStore variable which in turn triggers again the useEffect and so on. Is this assumption correct or am I misunderstanding anything else? And how would I resolve this to achieve what I need?

AGrig React get valued from getDisplayedRowCount() into container

I can successfuly console.log the value by doing
console.log(this.gridApi.getDisplayedRowCount());
inside onGridReady on my component.
id like to get this valued and pass it from this component over to another component so I can display the number of rows each time.
It would be best to use local state.
Then set local state to be the value of this.gridApi.getDisplayedRowCount()
React will then take care of the re-rendering.
But you will be able to use state to render the data.

Fetch graphql query result on render and re-renders BUT LAZILY

I have a React Apollo app and what I am trying to do is that I have a component that renders some data using charts. For this data, I have some filters that I save in the local state of the component (Using hooks)
const [filters, setFilters] = useState(defaultFilters);
Now what I want is that whenever the component mounts, fetch the data using the default filters. But I also want to re-fetch data when the user updates the filters AND CLICKS ON SUBMIT and I'd fetch the results using new filters.
Since I also want to fetch the results on filter update, I am using useLazyQuery hook provided by apollo
const [getData, {data}] = useLazyQuery(GET_DATA_QUERY, { variables: {filters} });
useEffect(getData, []); // this useEffect runs only when the component mounts and never again
But, what happens is whenever my state, filters, updates the getData function is automatically run! ALWAYS! (BEHIND THE SCENE)
How do I handle such cases, where I want to fetch results on mounting and re-rendering.
I have tried using useQuery and refetch provided by it but I get the same problem there, whenever I update the state, the component rerenders and the useQuery hooks is run and makes the call. (That's how I believe it runs)
How do I fix my current code. Calling the getData function inside the useEffect function makes it run on every re-render.
I think I the problem defined in this stackoverflow-question is somewhat similar to mine.
Part of the problem is that you really have two different states that you're trying to utilize a single hook for. You have state that represents your inputs' values in the UI, and then you have state that represents the filters you want to actually apply to your charts. These are two separate bits of state.
The simplest solution is to just do something like this:
const [inputFilters, setInputFilters] = useState(defaultFilters)
const [appliedFilters, setAppliedFilters] = useState(inputFilters)
const { data } = useQuery(GET_DATA_QUERY, { variables: { filters: appliedFilters } })
const handleSubmit = () => setAppliedFilters(inputFilters)
const handleSomeInputChange = event => setInputFilters(...)
This way, you use inputFilters/setInputFilters only to manage your inputs' state. When the user clicks your submit button, the appliedFilters are set to whatever the inputFilters are at the time, and your query will update to reflect the new variables.

Categories