I am using IntersectionObserver
api for implementing infinite scroll. When callback is called ,then inside the callback
,redux state does not have updated value.The functions are:
//function for defining InfiniteScroll
const InfiniteScroll = (parent,target,options,callback,getObject)=>{
const Infoptions = {
root: parent,
rootMargin: '50px',
threshold: 1.0,
...options
}
let observer = new IntersectionObserver(callback, Infoptions);
observer.observe(target);
getObject(observer);
}
export default InfiniteScroll;
This function is used here:
//calling InfiniteScroll
const target = useRef();
const parent = useRef();
const observer = useRef();
const state = useSelector((state)=>state);
useEffect(() => {
if(!loading){
InfiniteScroll(parent.current, target.current, {}, callbackScroll, function (obs) {
observer.current = obs;
})
}
return () => {
observer.current&&observer.current.disconnect();
}
}, [loading])
const callbackScroll = useCallback((data, observer) => {
if (data[0].isIntersecting) {
if ((state.post.data[postid]?.hasmorecomments) !== false){
//if there are more comments ,then this function will call api to fetch comments
FetchPostComments();
//here (state.post.data[postid]) returns undefined value,
//which is the initial value(when component has not mounted),
//but in some_other function ,it returns updated value
console.log((state.post.data[postid]));
}
}
},[FetchPostComments])
const some_other = ()=>{
//here it logs expected value(an object,not undefined)
console.log(state.post.data[postid]);
}
I want the updated value inside callbackScroll
function just like the function some_other
. How may i achieve it?
Edit-1 : jsx code where target is being used
//parent is the reference to scrollable div
return (
<div ref={parent}>
<Comments/>
{//here too, state.post.data[postid] has updated value}
{((state.post.data[postid]?.hasmorecomments) !== false)&&<Loader/>}
<div ref={target}></div>
</div>
)
CodePudding user response:
The purpose of using a useCallback
is to avoid unnecessary function invocation every time when a parent component or self is re-rendered, this is achieved by returning a memorized version of the callback function, that is invoked only when the state or reference value in the dependency array change. The function inside the useCallback
is executed only once when the component is initially mounted with initial state values.
Hence, it is returning undefined
. You'd want it to execute again when the state is updated (i.e invoke the function when the state is updated to contain more comments in this case). You can accomplish this by simply including the state in the dependency array of your useCallback
hook.
const callbackScroll = useCallback((data, observer) => {
if (data[0].isIntersecting) {
if ((state.post.data[postid]?.hasmorecomments) !== false){
//if there are more comments ,then this function will call api to fetch comments
FetchPostComments();
//here (state.post.data[postid]) returns undefined value,
//which is the initial value(when component has not mounted),
//but in some_other function ,it returns updated value
console.log((state.post.data[postid]));
}
}
},[FetchPostComments,state]) //Include state in dependency array
CodePudding user response:
The problem was basically with dependency array of useEffect
and useCallback
useEffect(() => {
if(!loading){
InfiniteScroll(parent.current, target.current, {}, callbackScroll, function (obs) {
observer.current = obs;
})
}
return () => {
observer.current&&observer.current.disconnect();
}
}, [loading,parent,target,callbackScroll,observer])
const callbackScroll = useCallback((data, observer) => {
if (data[0].isIntersecting) {
if ((state.post.data[postid]?.hasmorecomments) !== false){
//if there are more comments ,then this function will call api to fetch comments
FetchPostComments();
//here (state.post.data[postid]) returns undefined value,
//which is the initial value(when component has not mounted),
//but in some_other function ,it returns updated value
console.log((state.post.data[postid]));
}
}
},[FetchPostComments,state]) //Include state in dependency array