How to push Multiple Objects into an array using useState hook - react-hooks

I need to push the Multiple objects in to an array by using UseState hook,
Here I am getting the multiple objects into "getallData", So I need to sent the all the multiple objects into setdataObject. But here I am not getting all the multiple objects data and getting an Empty Array..
const [data, setData] = useState([])
const [dataObject,setdataObject] = useState([{}])
useEffect(()=>{
fetch('http://localhost:3000/results')
.then(res =>res.json())
.then((results)=>{
setData(results);
//console.log(results);
for(let i=0;i<results.length;i++){
//console.log(results);
const getallData={
name :`${results[i].name.first} ${results[i].name.last}`,
money : results[i].price.money.wealth
}
//console.log(getallData);
setdataObject(getallData);
console.log(dataObject);
}
})
},[])

You are calling setdataObject inside a loop. Rather you can add the all datas into an array and set it at the end of the loop. Something like this
const tempArray = []
for(let i=0;i<results.length;i++){
const getallData={
name :`${results[i].name.first} ${results[i].name.last}`,
money : results[i].price.money.wealth
}
tempArray.push(getallData)
}
setdataObject(tempArray);
Another thing. As setState functions are asynchronus so if you call console.log() immediately after changing any state value you will not get the changes immediately. As a result your following code is printing wrong output
setdataObject(getallData);
console.log(dataObject); // WRONG !!!!

Related

Transform data after it received from graphql server using vue-composition api

this is my first try of front end developing, so I mostly copy-pasting example is the net.
import {useQuery, useResult} from "#vue/apollo-composable";
export default defineComponent({
name: 'Components',
setup() {
const {result: modulesResult} = useQuery(getModules)
const result = useResult(modulesResult)
return (result)
}
})
I've written the following code and while I can use result in templates (v-for or v-if), I can't find the way how to transform my data.
I want to take the value of result and apply transformation function and pass transformed value to templates. result is vue ref and value is not available if I write ref(result).value right after useResult
const test = ref(result).value
console.log(test) <- undefined
useQuery contains onResult return value, it triggers on data updates, for example
const {onResult} = useQuery(getDerivativeInstruments)
onResult((resultData) => {
instruments.instruments = resultData!!.data.getDerivativeInstruments
instruments.filteredInstruments = resultData!!.data.getDerivativeInstruments
})

How do you get data back from a react-redux store?

Using React-Redux
I have a select list that when the user chooses one of the options, a item is created and placed in the database (if it matters, the reason its a select box is that there are multiple variations of the same item and what variation is important).
This is working correctly.
My problem is that I am not sure how I can get the id of the new item out of the redux store.
And just for chuckles, the prior developer set all this up with sagas. So I am still coming up to speed on how it all works together.
So when the select box is checked, the function checkFunction is called that calls the function createItem in the saga file. These functions are below:
in Repositories.jsx
checkFunction = (data) => {
const {createItem} = this.props;
// data holds the info that we need to send to the action
const created = createItem(data);
// once data comes back, redirect the user ot the details of the created item
// need id of created item
// navigateTo(`/item-details/${created.id}`);
}
in Repositories.saga.js
export function* createItem(action) {
try {
const {payload: newItem} = action;
// call api to create item
const created = yield call(requestAPI.post, ITEMS_URL, newItem);
// send message that its been done
yield put(actions.repositories.createItem.ok(created));
// send message to refresh item list
yield put(actions.inventories.fetchItems.start());
} catch (e) {
yield put(actions.repositories.createItem.fail(e));
}
}
I don't understand how to return the id of the created item once its created. I feel like I am missing something basic here. Can anyone point me in the right direction?
Actually getting data from saga back to react component is not trivial. There are multiple approaches to do what you need although each has its downside.
1. Call navigateTo in the saga.
export function* createItem(action) {
...
const created = yield call(requestAPI.post, ITEMS_URL, newItem);
yield call(navigateTo, `/item-details/${created.id}`)
}
This would be my recommended solution if you can get the navigateTo function into the saga. Navigation is a side effect and sagas are there to deal with side effects. Make sure to use the call effect, changing the url by directly calling the function can lead to some issues.
2. Store the latest created item id in redux store
In your reducer, when action actions.repositories.createItem.ok(created) is dispatched, store the created item info and then send the latest created item to the component. Finally you can use componentDidUpdate or useEffect to call navigateTo when the prop changes.
render() {
const created = Redux.useSelector(state => state.created);
useEffect(() => navigateTo(`/item-details/${created.id}`), [created])
...
}
This has the disadvantage that the component will rerender becuase of the changed created value.
3. Send callback in the createItem action
You can put a function into your action and then call it from the saga and essentially using it as a callback.
Component:
checkFunction = (data) => {
const {createItem} = this.props;
// data holds the info that we need to send to the action
const created = createItem(data, (created) => {
navigateTo(`/item-details/${created.id}`);
});
}
Saga:
export function* createItem(action) {
...
const created = yield call(requestAPI.post, ITEMS_URL, newItem);
action.callback(created)
...
}
The problem with this approach is that functions are not serializable and so you ideally should avoid them in your actions. Also, technically, there could be multiple sagas handling the same action and then it gets kind of confusing who should call the callback.

useLazyQuery and useQuery onCompleted not running when variable doesn't change or is changed to null

What i want to do: I have a few category toggle buttons. I want to show only the data of the categories that has been checked.
My approach: The function for showing the filtered data checks the array of buttons, see which one is ticked, then reads the cache of the query.
const getFilteredData = () => {
try {
const freshFilteredData = []
for (var i = 0; i < chipData.length; i ++){
if (chipData[i].clicked){
const itineraryData = client.readQuery({
query: GET_ITINERARY,
variables: {itineraryId : chipData[i].label}
})
const wantedData = itineraryData.getItinerary.dayPlans;
freshFilteredData.push(wantedData)
}
}
setFilteredData(freshFilteredData)
} catch (err) {
console.log(err)
}
}
However, cache can only be read when a query has been fired. So I use an if-else statement to decide when to call the getFilteredData function. If the button is just checked, then I call the query (when it's completed it will call the getFilteredData function), if the button is unchecked, I call the getFilteredData directly.
const toggleClick = clickedChip => () => {
const chipClone = [...chipData];
const objectIndex = chipData.findIndex(
chip => chip.key === clickedChip.key
);
chipClone[objectIndex].clicked = !chipData[objectIndex].clicked;
setChipData(chipClone);
if (chipClone[objectIndex].clicked) {
getItinerary({variables: {itineraryId: clickedChip.label}});
} else {
console.log('fire2')
getFilteredData();
}
};
And here's my lazy query:
const [getItinerary] = useLazyQuery(GET_ITINERARY, {
onCompleted(data){
console.log('fired');
getFilteredData()
}
});
My problem: if I clicked on the same button thrice.
click (runs query)
unclicked (doesn't run query)
clicked (doesn't run query, so doesn't run getFilteredData function, because query doesn't run
onCompleted. And since it is clicked, it doesn't execute the 'else' statement either, so getFilteredData is not run at all)
That screws up the filtering.
I could get rid of the if-else statement and execute the getFilteredData function at two places:
const toggleClick = clickedChip => () => {
const chipClone = [...chipData];
const objectIndex = chipData.findIndex(
chip => chip.key === clickedChip.key
);
chipClone[objectIndex].clicked = !chipData[objectIndex].clicked;
setChipData(chipClone);
getItinerary({variables: {itineraryId: clickedChip.label}});
getFilteredData();
};
This will cover all bases, but I was wondering if there's a more elegant way to do it?
the thing you have missed is apollo by defaults stores the result of all issued query in its local cache, any subsequent call to a query fetches the result from cache(unless you have changed the fetch policy).
instead of we manually checking whether its a first time call, delegate that responsibility to apollo.
My recommendation for the flow would be
1) maintain a state variable for the clicked chip label
2) change the above label in the onClick callback of the chip, that will fire the query
3) let apollo decide whether its a first time call or subsequent call
const [chipLabel, setChipLabel] = useState(<Initial label here>) // pass the initial value
//that query expects
// pass the state variable above in the query
const itineraryData = useQuery({
query: GET_ITINERARY,
variables: {itineraryId : chipLabel}
})
// all the toggle button should have a click handler like below
onClick={() =>{//call the setChipLabel}}
Open the network tabs, click any filter button multiple times, only during the first click a n/w call will be issued. Apollo client is smart to read from the cache, if the data is already available, by default the fetch policy is "cache-first".

console.log(..) of 'reselect' selector displays f()

I'm using react-boilerplate that uses reselect for reading the redux state and maps it to props. I am trying to read the redux state outside a react component (say in custom function defined in myUtil.js).
There is selector in selectors.js:
const makeSelectLoading = () => createSelector(selectGlobal, globalState => globalState.get('loading'));
I import makeSelectLoading into myUtil.js and try to print the value using console.log(makeSelectLoading()). I am expecting the value of the Loading state variable, instead I'm getting the below:
myUtil.js?d403:14 ƒ () {
if (!areArgumentsShallowlyEqual(equalityCheck, lastArgs, arguments)) {
// apply arguments instead of spreading for performance.
lastResult = func.apply(null, arguments);
}
Should I expect this to work? If not, any ideas where I'm going wrong? Thanks!
makeSelectLoading is not a selector itself but a selector factory: a function which returns an actual selector.
In order to use it you should get a selector instance from it and then call the returned instance with the expected arguments.
const getSelectLoading = makeSelectLoading();
const loadingState = getSelectLoading(state);

Return a Javascript Promise value AKA Keras.js prediction

I'm new to Javascript and getting a bit bogged down with Promises in regards to predictions in Keras.JS
Basically i need to get the prediction value out of a promise (Keras Model) so I can pass it to another function. The following code is taken from the Keras.js github.
var predictions = function () {
model
.ready()
.then(() => {
// input data object keyed by names of the input layers
// or `input` for Sequential models
// values are the flattened Float32Array data
// (input tensor shapes are specified in the model config)
console.log('Model ready',x_pred )
var inputData = {
"input": new Float32Array(x_pred)
};
console.log('input data ready')
// make predictions
return model.predict(inputData)
})
.then(outputData => {
// outputData is an object keyed by names of the output layers
// or `output` for Sequential models
// e.g.,
// outputData['fc1000']
//console.log("outputData", outputData)
const output = new Float32Array(outputData.output)
console.log( output )
})
};
Now, the console reads the contents of my prediction - so the model is doing what I want it to do. But I need to take that prediction and pass it to another function. The following just points to my model promise and the output is undefined.
console.log(outpreds, output)
I understand that this is how the promise is meant to work but once the promise has been fulfilled I would really like to be able to do further things with output. unfortunately as I am using Electron/NodeJS I can't access async/await
Can anyone point me in the right direction?

Resources