I am trying to get data Using useInfiniteQuery, but on my console, I am getting the data but the pageParams is showing undefined, am I missing something to get the pageParams?
Here is my query hook
const useActivityFeedData = () => {
const {data} = useInfiniteQuery(
ACTIVITY_FEED,
({pageParam}) => Api.user.getActivityFeedData(pageParam),
{
getNextPageParam: (lastPage: any) => lastPage?.meta,
},
);
console.log(data)
};
My API
getActivityFeedData: (pageParam: number) => {
console.log(pageParam, 'pageParam'); // undefined
return api.get(
`/rest/s1/eyon/viewer/channel/activity-feed?pageSize=10&pageIndex=0`,
{},
{},
);
},
You're not missing anything - this is the intended behaviour. pageParams is always calculated for the next page, usually from the previous result. That's what you do in getNextPageParams.
For the first page, there is no "previous result", because it is the first page. That's why the pageParams are undefined. Note how we use default values during destructuring in the examples, e.g.:
const queryResult = useInfiniteQuery(
['projects'],
({ pageParam = 0 }) => axios.get('/api/projects?cursor=' + pageParam),
{
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
}
)
for the first page, the cursor will be set to 0, as pageParam is undefined.
So it's just up to you to convert undefined to something that represents "the first page" for your api call.
Related
I want to change the data of a state object but Redux Toolkit is not changing and gives an error like Uncaught TypeError: Cannot assign to read only property 'status' of object '#<Object>'.
These lines from component:
const [width, setWidth] = useState(8)
const [height, setHeight] = useState(9)
const [table, setTable] = useState({
rows:
[...Array(height)].map(()=>
(
{
cells:
[...Array(width)].map(()=>
(
{status: true}
)
)
}
)
)
})
useEffect(()=>{
dispatch(changePlayableFields(table)) // <- it's not changing the state
},[table])
function changeCell(i:number,k:number){
const localTable = {...table}
localTable.rows[i].cells[k].status = !localTable.rows[i].cells[k].status // <-Uncaught TypeError: Cannot assign to read only property 'status' of object '#<Object>'
setTable(localTable)
}
changeCell function is working very well and I see the truth results on the page. But when adding useEffect codes to move new datas to keep them in memory with redux, then I get the errors.
And these are from Redux Slice:
import { createSlice } from "#reduxjs/toolkit"
const levelSlice = createSlice({
name: "level",
initialState: {
gridSizeAndPlayableFields: {
width: 8,
height: 9,
playableFields: {
rows:
[...Array(9)].map(()=>
(
{
cells:
[...Array(8)].map(()=>
(
{status: true}
)
)
}
)
)
}
},
},
reducers: {
changePlayableFields: (state, action) => {
state.gridSizeAndPlayableFields.playableFields = action.payload // <- it's not changing the data
},
}
})
export const {changeGridSize, changePlayableFields} = levelSlice.actions
export default levelSlice.reducer
It's little about my previous question, maybe you'd like to check it. Here is my previous question link: Redux Slice is returning an error after adding a function into a property of initial states
I hope anyone can help. Thanks...
1. Reducer does not update issue:
It seems you are sending rows as payload of the dispatch. So you should update gridSizeAndPlayableFields.playableFields.rows in the reducer:
changePlayableFields: (state, action) => {
// console.log(action.payload);
state.gridSizeAndPlayableFields.playableFields.rows = action.payload.rows;
// console.log(current(state.gridSizeAndPlayableFields.playableFields));
},
2. object update issue in changeCell method:
In a normal function you cannot mutate the object like in changeCell function. You can only do this in the redux toolkit slice thanks to Immer.
You can map the rows and cells arrays to update the corresponding indeces' status values. You can write the changeCell method in the following way:
function changeCell(i, k) {
if (!table) return;
const localTable = {};
const localTableRows = [...table.rows];
// map rows array
const updatedRows = localTableRows.map((item, index) => {
// if index equals i, map its cells as well
//... and find kth cell and change its status
if (index === i) {
return {
...item,
cells: item.cells.map((c, idx) => {
if (idx === k) {
return {
...c,
status: !c.status,
};
}
// if idx not equals to k return old cell item
return c;
}),
};
}
// if index is not equal i return old row item
return item;
});
localTable.rows = updatedRows;
setTable(localTable);
}
I suppose i and k index values for the zero based array.
You can use Object.reduce method to calculate updated table object in your changeCell function; but personally I try to avoid from this because in general Object.reduce is less performant.
I am developing a React Native application and am facing the following error:
I have defined a useRef which stores the doc ID from a firebase collection. But when I call that variable after it has been defined, the .current value returns a blank string.
db.collection('users').onSnapshot((snapshot) => {
snapshot.docs.map((doc) => {
if (doc.data().email === auth.currentUser?.email) {
bidId.current = doc.id
console.log(bidId.current)
}
})
})
The above code returns the expected value. However, when I call the variable outside this db.collection loop, I get the following value:
But calling the bidId.current returns a blank string.
Please can someone help me with this. Thanks!
Actually this is what happens:
db.collection('users').onSnapshot((snapshot) => {
snapshot.docs.map((doc) => {
if (doc.data().email === auth.currentUser?.email) {
bidId.current = doc.id
// This line gets executed after some time!
console.log(bidId.current)
}
})
})
// This gets executed first! (The value has not been stored yet!)
console.log(bidId.current);
Using the "useState" hook instead of "useRef" will solve the issue. Consider the following code:
const [BidId, setBidId] = useState<string | null>(null);
// This will store the value...
useEffect(() => {
db.collection('users').onSnapshot((snapshot) => {
snapshot.docs.map((doc) => {
if (doc.data().email === auth.currentUser?.email) {
setBidId(doc.id);
}
})
})
}, []);
// Here you can access the value
useEffect(() => {
if(BidId !== null)
console.log(BidId);
}, [BidId]);
// You can also return the component like the following:
return (<View>The Bid ID is: {BidId !== null ? BidId : "Loading..."}</View>);
Your useEffect basically says that whenever pageRef changes, call this function. If done outside, it will call do your tasks on every render instead of doing the whenever pageRef values is changed. Also, in initial renders, it may give undefined values.
You can only return a function in useEffect which basically says that before running the same next time, run this function before.
Try (currentUser without the '?' query character):
if (doc.data().email === auth.currentUser.email) {
bidId.current = doc.id
console.log(bidId.current)
}
I have read several cases on stackoverflow regarding missing dependencies in useEffect:
example :
How to fix missing dependency warning when using useEffect React Hook?
Now the case I have is, I use useEffect for pagination:
Here's the source code:
react-router-dom configuration
{ path: "/note", name: "My Note", exact: true, Component: Note },
Note Component
const Note = (props) => {
const getQueryParams = () => {
return window.location.search.replace("?", "").split("&").reduce((r, e) => ((r[e.split("=")[0]] = decodeURIComponent(e.split("=")[1])), r),
{}
);
};
const MySwal = withReactContent(Swal);
const history = useHistory();
// Get Queries On URL
const { page: paramsPage, "per-page": paramsPerPage } = getQueryParams();
// Queries as state
const [queryPage, setQueryPage] = useState(
paramsPage === undefined ? 1 : paramsPage
);
const [queryPerPage, setQueryPerPage] = useState(
paramsPerPage === undefined ? 10 : paramsPerPage
);
// Hold Data Records as state
const [notes, setNotes] = useState({
loading: false,
data: [],
totalData: 0,
});
useEffect(() => {
console.log(queryPage, queryPerPage);
setNotes({
...notes,
loading: true,
});
// Fetching data from API
NoteDataService.getAll(queryPage, queryPerPage)
.then((response) => {
setNotes({
loading: false,
data: response.data,
totalData: parseInt(response.headers["x-pagination-total-count"]),
});
return true;
})
.catch((e) => {
MySwal.fire({
title: e.response.status + " | " + e.response.statusText,
text: e.response.data,
});
});
return false;
}, [queryPage, queryPerPage]);
const { loading, data, totalData } = notes;
...
So there are two problems here:
There is a warning React Hook use Effect has missing dependencies: 'MySwal' and 'notes'. Either include them or remove the dependency array. You can also do a functional update 'setNotes (n => ...)' if you only need 'notes' in the 'setNotes' call. If I add notes and MySwal as dependencies, it gives me a continuous loop.
When I access the "note" page, the Note component will be rendered.
Then, with pagination: / note? Page = 2 & per-page = 10, it went perfectly.
However, when returning to "/ note" the page does not experience a re-render.
Strangely, if a route like this / note? Page = 1 & per-page = 10, returns perfectly.
Does my useEffect not run after pagination?
First of all, move your API call inside of useEffect. After your data is fetched, then you can change the state.
useEffect(() => {
//Fetch the data here
//setState here
},[]) //if this array is empty, you make the api call just once, when the `component mounts`
Second Argument of useEffect is a dependancy array, if you don't pass it, your useEffect will trigger in every render and update, which is not good. If you parss an empty array, then it makes just one call, if you pass a value, then react renders only if the passed value is changed.
I am trying to use the custom render for a search box. I am using semantic-ui-react.
Following is a code snippet for the render method :
render() {
const { isLoading, value, results } = this.state
const resultRenderer = ({ clientName }) => (
<div>
<p>{clientName}</p>
</div>
);
resultRenderer.propTypes = {
clientName: PropTypes.string
}
return (
<Search
loading={isLoading}
onResultSelect={this.handleResultSelect}
onSearchChange={_.debounce(this.handleSearchChange, 10, {loading: true})}
results={this.state.results}
value={value}
resultRenderer={this.resultRenderer}
{...this.props}
/>
)
}
}
The code snippet below is the handleSearchChange method :
handleSearchChange = (e, { value }) => {
var resultsArray = []
this.setState({ isLoading: true, value })
api.autoCompleteClient(value).then(res => {
var tempArray = res.data.data.hits.hits
var autoResult = []
for(var i = 0; i < tempArray.length; i++)
{
resultsArray.push(tempArray[i]._source.clientName)
}
}).catch(error => {
console.log('Some error got while performing autocomplete for clients ', error)
})
setTimeout(() => {
if (this.state.value.length < 1) return this.setState(initialState)
this.setState({
isLoading: false,
results: resultsArray,
})
}, 300)
}
The results in the render when printed can be seen in the following screenshot :
However, the results in the search bar are empty and I am getting the following errors as can be seen below :
Inside the result renderer if I put a print statement, I get the following results :
Any ideas as to what I may be doing wrong. All help would be greatly appreciated!
I think this line is the culprit:
resultsArray.push(tempArray[i]._source.clientName)
Not sure what your data looks like, but if you have three empty results and there are three results, I'm guessing it's not grabbing the right property.
It looks like you need to set the state in the .then() callback for api.autoCompleteClient. This way you know the data is ready, instead of just waiting for 300ms.
I also suggest using Array.map() instead of the for loop for brevity/showing intent.
And just a heads up, using the React Devtools extension in Chrome lets you examine the state/props of components in real-time.
As for the first first two console warnings, I would just look in SemanticUI docs and see what the props are for that component, it looks like two aren't actually used.
The last warning just meaning you need a key prop when mapping multiple components, to help render them more efficiently. So just key={someUniqueValue}.
Edit: Try this :)
const resultRenderer = (data) => {
debugger;
return (
<div>
<p>{data.clientName}</p>
</div>
);
}
can you also paste your code in search component?
I was able to get it working with help from #adamz4008.
The updated code for handleSearchChange with the corrections looks as follows:
handleSearchChange = (e, { value }) => {
var resultsArray = []
this.setState({ isLoading: true, value })
api.autoCompleteClient(value).then(res => {
var tempArray = res.data.data.hits.hits
var autoResult = []
for(var i = 0; i < tempArray.length; i++)
{
//Converted every result into an object
//Semantic React UI renders objects
var result = {clientName : tempArray[i]._source.clientName}
resultsArray.push(result)
}
}).catch(error => {
console.log('Some error got while performing autocomplete for clients ', error)
})
setTimeout(() => {
if (this.state.value.length < 1) return this.setState(initialState)
this.setState({
isLoading: false,
results: resultsArray,
})
}, 300)
}
Also the result renderer looks as follows after correction :
const resultRenderer = (data) => {
console.log('Inside resultRenderer ', data)
return (
<div>
<p>{data.clientName}</p>
</div>
);
}
I'm having trouble with setState when using the package: reactn
When I replace these lines (1) with those lines (2), the code works. The (2) is a workaround, deals with asynchronous setState, but I want to understand why (1) doesn't work.
As I know, I can pass a callback function to setSomeState in React Hooks:
If the new state is computed using the previous state, you can pass a function to setState
This is also another usage of useGlobal from the document of reactn, which also uses a callback function as an argument for setGlobal. Why their example works but mine doesn't?
Full code: https://snack.expo.io/#loia5tqd001/d26e8f
Snippets:
listSymbols = [ "USD", "EUR", ... ]
usdRates = {} // expect to be usdRates = { USD: 1, EUR: 0.9 ... }
// getExchangeRate is in utils/utils.js
// => The code doesn't work
for (const symbol of listSymbols) {
getExchangeRate("USD", symbol).then(exchangeRate => {
setUsdRates(oldUsdRates => ({
...oldUsdRates,
[symbol]: exchangeRate
}))
.then(() => console.log("Call api getting exchange rate for " + symbol, usdRates) )
})
}
// => The code works as expected
for (const symbol of listSymbols) {
getExchangeRate("USD", symbol).then(exchangeRate => {
usdRates[symbol] = exchangeRate
console.log("Call api got exchange rate for " + symbol, usdRates)
})
}
setUsdRates(usdRates)
Based on the source of reactn it doesn't appear that the updater function style is supported when using the useGlobal('propertyName') version of the hook.
Here is the definition of the property setter: https://github.com/CharlesStover/reactn/blob/master/src/use-global.ts#L95
You can see it creates a newGlobalState object and passes it to setGlobal.
Then setGlobal calls the set on the global state manager here: https://github.com/CharlesStover/reactn/blob/master/src/global-state-manager.ts#L302
Since newGlobalState from the property setter is always an object, the updater version is never used.
You could achieve what you want by passing nothing to useGlobal and dealing with the entire state object instead, as per the example in the docs that you linked:
const [global, setGlobal] = useGlobal();
...
getExchangeRate("USD", symbol).then(exchangeRate => {
setGlobal(oldGlobal => ({
...oldGlobal,
usdRates: {
...oldGlobal.usdRates,
[symbol]: exchangeRate,
},
}))
.then(() => console.log("Call api getting exchange rate for " + symbol, usdRates) )
})
}
Also I'm not sure your other example is 100% correct - you're not waiting to call setUsdRates until all of the async getExchangeRate calls are complete.
Okay I will try to clear some things here
as you said
usdRates = {} // expect to be usdRates = { USD: 1, EUR: 0.9 ... }
So it's supposed to be an object
const [usdRates, setUsdRates] = useGlobal({})
then do
useEffect(() => {
for (const symbol of listSymbols) {
getExchangeRate("USD", symbol).then(exchangeRate => {
setUsdRates(oldUsdRates => ({
...oldUsdRates,
[symbol]: exchangeRate
}))
.then(() => console.log("Call api getting exchange rate for " + symbol, usdRates)
)
})
}
}, [])
Hope it helps