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

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);

Related

Proper way to call RTK Query endpoint.select() with no arguments (and skip options)

I would like to use the endpoint.select() function to create selectors from cached RTK Query data, see RTK Advanced Patterns.
The documentation clearly states that if there is no query argument, you can pass undefined to select() (see the Selecting Users Data section).
However, in my case this does not work unless i trigger the query by the initiate() function. When triggering the query from the query hook on the other hand, the selector fails to retrieve the cached data.
The not working setup here is pretty simple:
export const productsApi = createApi({
baseQuery: fetchBaseQuery({ baseUrl: API.ENDPOINTS.PRODUCTS }),
reducerPath: 'productsApi',
endpoints: (builder) => ({
listAllProducts: builder.query({
query: ()=>'/list',
}),
}),
});
export const { useListAllProductsQuery } = productsApi;
Then in a customHook I call the useListAllProducts hook:
const {
data,
} = useListAllProductsQuery({skip:shouldSkip});
And finally in the selector:
export const selectProducts =
productsApi.endpoints.listAllProducts.select(); //undefined param as docs recommend
Potential Fix: (or more like a hacky workaround):
Strangely enough, I discovered that if i pass an argument (aka cacheKey) into the select function and pass that same cacheKey into the query hook, all of a sudden the stars align and everything works (although the docs state this is not necessary). So the modified code looks like:
// in selector
export const selectProducts =
productsApi.endpoints.listAllProducts.select('products');
// in hook
const {
data,
} = useListAllProductsQuery('products');
Im wondering if anyone can shed some wisdom on why this works, or even better can
recommend the best practice for utilizing the select function on a query with no cacheKey (since the docs seem incorrect or outdated?).
I would also like to point out, when calling select() without a parameter, a typescript warning surfaces indicating a parameter is required.
I am not certain where you think that the docs do state that you do not need an argument.
You will need to call select with the same argument as you call your hook to get a selector for that cache key - so if you call useMyQuery(), you can call select() - and if you call useMyQuery(5), you can call select(5) to get a selector for the cache key 5.
Those are individual cache entries and you will need a selector for each of those cache entries.
Also, could you clarify what exactly you mean by "not working"? Using the selector will give you only the cache entry, but not make a request - you are after all just selecting from the store. So before you used the hook or dispatched initiate, you will get an uninitiated cache entry.
I think, this can solve your problem
in component.jsx file
const state = useSelector((state: RootState)=>state);
console.log(getState(state, params));
in api.js file
export const getState = (state: RootState, params) => api.endpoints.getApiState.select(params)(state);

How to push Multiple Objects into an array using useState hook

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 !!!!

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
})

Passing values between React components with useState

I use a React component with Apollo client as function component. The function body of my main search component looks like this:
function SearchContainer(props) {
const [begTime, setBegTime] = useState('')
const runSearch(begin_time) {
console.log('begin_time: ', begin_time) <== The printed value is Ok!
setBegTime(begin_time) <=== Use hook to set the value of begTime
console.log('begTime: ', begTime) <=== The output shows no change in begTime. Why?
}
return (
// Use SearchForm to get the search parameters.
<SearchForm
handleSearch={runSearch} <== Use SearchForm to get begin_time back into this component.
/>
// Provide the parameters from SearchForm and run the useQuery from Apollo using this parameters.
<SearchResults
begTime={begTime}
/>
)
}
The SearchForm is just a usual form as a React function component with useState hooks and calls on form submit the hanldeSearch function.
function SearchForm({handleSearch}) { <== handleSearch function from the parent component.
const handleSubmit = (begin_time) => {
handleSearch(begin_time) <== This call works and the value will be provided to the parent.
}
...
}
My idea of this code is to create 2 independent components. One component (SearchForm) should get the parameters. The other component (SearchResults) will get this parameters as arguments, run the query using useQuery and show the results.
But the useState hook does not work very well in my case. Interesting enough if I call the corresponding search form twice, I can see in the runSearch function, that the begTime has got the previous search values and not the initial value. So apparently the useState kind of works, but I want to run the search with the current values and not with the previous ones.
Is it possible at all to create such components with React hooks? It's my first big test with hooks instead of classes.
Thanks in advance
Andrej
For your question
const runSearch(begin_time) {
console.log('begin_time: ', begin_time)
setBegTime(begin_time)
console.log('begTime: ', begTime) <=== The output shows no change in begTime. Why?
}
The output shows no change in begTime. Why?
As stated in docs when we set state that is async function.
By that i mean your code will keep running and to set state react will start child process on another thread. And when its complete it will pass result to main thread. ( that you can c in useEffect or componentDidUpdate for early version).
So Main points are
at setBegTime(begin_time) async process is started
at main thread code will not wait for it
So next statement that is console.log('begTime: ', begTime) is processed and u saw no changes as in actual its value is not updated yet. React is still updating value.
Updating process is async because React dont want to main thread to wait for heavy work ( updating state is heavy process ) as if it wait then webpage will not respond untill it is completed. So it instead run that process on another thread.
For second one
you can try this
function SearchContainer(props) {
const [begTime, setBegTime] = useState('')
const [response,setResponse] = useState({})
useEffect(()=>{
const runSearch = (begin_time) {
setBegTime(begin_time)
}
},[begin_time])
// u can rather define working of handleSubmit in parent component and <br/>
// store its output in state and then pass it to another component
const handleSubmit = (begin_time) => {
resp = handleSearch(begin_time)
setResponse(resp)
}
return (
// Use SearchForm to get the search parameters.
<SearchForm
handleSearch={()=>handleSubmit()}
/>
// Provide the parameters from SearchForm and run the useQuery from Apollo using this parameters.
<SearchResults
begTime={begTime}
response={response}
/>
)
}

RxJS: How to delay execution of the ELSE in RxJS.Observable.if?

I have an object that might or might not exist. I'm using Observable.if to determine what action to do based on its existence.
However, the else part of Observable.if seems to be running even when the object is undefined. I get this error: TypeError: Cannot read property 'genesisHash' of undefined
console.log("jjjjjjjjjjjjjjjj: ", t); // prints out jjjjjjjjjjjjjjjj: undefined
return Observable.if(
() => !t,
Observable.of(nodeActions.requestGenesisHashes()),
Observable.of(
nodeActions.treasureHunt({
genesisHash: t.genesisHash // error occurs here
})
)
);
How would I delay the call to nodeActions.treasureHunt so that it doesn't try looking at the genesisHash attribute on t?
I'm using this through redux-observable by the way. Hence using actions.
Your then/else observable creation is not wrapped in a function, so the else observable setup code is ran when passing to the Observable.of(...) function. You probably need to just use regular if/else type of logic:
const actions = !t ? nodeActions.requestGenesisHashes() :
nodeActions.treasureHunt({ genesisHash: t.genesisHash });
return Observable.of(actions);
If you really wanted to use that method, you could just create the Observable manually:
return Observable.if(
() => !t,
Observable.of(nodeActions.requestGenesisHashes()),
Observable.create(obs => {
obs.next(nodeActions.treasureHunt({ genesisHash: t.genesisHash }));
obs.complete();
});
);
That should delay the use of the t variable until something tries to subscribe to the observable, which will never happen.

Resources