useState not triggers rerendering in websocket callback handler - reactjs

Using web socket(#aspnet/signalr) it works fine(in component callback is receiving the message)fine, I am able to receive and trigger callback in component(connection.on("UpdateProgress"... ) inside this callback its increment counter which is state variable(numberOfFailed).. it triggers rendering only once, I set debugger and see numberOfFailed is always 0.
What's wrong here? why calling setNumberOfFailed doesn't change the value of numberOfFailed.
here is the code;
const [numberOfFailed, setNumberOfFailed] = useState(0);
const [connection, setConnection] = useState(null);
useEffect(() => {
const newConnection = new HubConnectionBuilder()
.withUrl(`${config.API_BASE_URL}update-progress`, {
transport: HttpTransportType.WebSockets,
accessTokenFactory: () => {
return `${localStorage.token}`;
},
})
.build();
setConnection(newConnection);
}, []);
useEffect(() => {
const fetchData = async () => {
if (connection) {
try {
await connection.start();
connection.onclose((error) => {
console.info('Connection Closed:', error);
});
if (connection.state === HubConnectionState.Connected) {
connection.on('UpdateProgress', (message) => {
debugger;
if (message.count) {
setTitleText(`Bildirim Gonderim Başladı, Toplam Alıcı Sayısı:${message.count}`);
} else if (message.status == 1) {
let _t = numberOfFailed + 1;
setNumberOfFailed(_t);
}
console.info('message', message);
});
}
} catch (err) {
console.log(err);
}
}
};
fetchData();
}, [connection]);

It was because react not trace the updated of variables which not explicitly defined in DependencyList. The best solution for this change the way..
This is how I solve this problem;
The main idea is using useReducer hook to update variables and use them in render.
const [connection, setConnection] = useState(null);
const [counts, dispatch] = useReducer(BaskentMobilReducer, INITIAL_VALUE);
useEffect(() => {
const newConnection = new HubConnectionBuilder()
.withUrl(`${config.API_BASE_URL}update-progress`, {
transport: HttpTransportType.WebSockets,
accessTokenFactory: () => {
return `${localStorage.token}`;
},
})
.build();
setConnection(newConnection);
}, []);
useEffect(() => {
const fetchData = async () => {
if (connection) {
try {
await connection.start();
connection.onclose((error) => {
console.info("Connection Closed:", error);
});
if (connection.state === HubConnectionState.Connected) {
connection.on("UpdateProgress", (message) => {
if (message.count) {
setTotalCount(message.count);
setTitleText(
`Bildirim Gonderim Başladı, Toplam Alıcı Sayısı:${message.count}`
);
} else if (message.status == 0) {
debugger;
dispatch({
type: "UPDATE_COUNTS_SUCCESS",
});
console.log("counts", counts);
} else if (message.status == 1) {
debugger;
dispatch({
type: "UPDATE_COUNTS_FAIL",
});
console.log("counts", counts);
}
console.info("message", message);
});
}
} catch (err) {
console.log(err);
}
}
};
fetchData();
}, [connection]);

Related

Possible Unhandled Promise Rejection (id: 0): React Native

I know what caused this error, I explicitly removed the header from axios call to check if the code can handle the error. But my question is I have a catch block in place, but I'm still getting this -> Possible Unhandled Promise Rejection
const getUser1 = () => {
userService.getUser1().then((res) => {
setId(res.data._id);
return Promise.resolve();
}).catch((error) => Promise.reject(error));
};
const getUserComments = () => {
commentsService.getUserComments(‘user1’).then((res) => {
setComments(res.data)
return Promise.resolve();
}).catch((err) => Promise.reject(err));
};
useEffect(() => {
const onInit = async () => {
await Promise.all([
getUser1(),
getUserComments(),
]).catch((ex) => console.log(ex));
};
onInit();
}, []);
Try this version:
const getUser1 = async () => {
try{
const {data} = await userService.getUser1()
setId(data._id);
}
catch(err){
throw new Error(err)
}
};
const getUserComments = async () => {
try{
const {data} = await commentsService.getUserComments(‘user1’)
setComments(data)
}
catch(err){
throw new Error(err)
}
};
const init = useCallback(async () =>{
try{
return await Promise.all([
getUser1(),
getUserComments(),
])
}
catch(err){
console.error(err)
}
}, [])
useEffect(() => {
init();
}, [init]);

How does infinite scroll work in case of caching redis

In case of no cache, infinite scroll works, but when you add cache code, the data repeats when pagination is finished. how can i solve. I am doing a clone project. I'm new to redis, I'd be very grateful if you could reply. I can't think of anything about it (:
Backend my code
const searchpost = async (req, res) => {
let perpage = 3;
const value = req.query.q;
const pageNumber = req.query.page;
try {
const redisPosts = await client.keys("Blog*");
if (redisPosts.length > 0) {
async.map(
redisPosts,
async function (redisPost) {
const cacheBlog = await client.get(redisPost);
let parseData = JSON.parse(cacheBlog);
let job = { ...parseData };
return job;
},
function (err, results) {
if (err) throw err;
res.status(200).json({ searcharticles: results });
}
);
} else {
const searcharticles = await Blog.find({
$or: [
{ title: { $regex: value, $options: "i" } },
{ tag: { $regex: value, $options: "i" } },
{ Subtitle: { $regex: value, $options: "i" } },
],
})
.skip((pageNumber - 1) * perpage)
.limit(perpage)
.populate("authorId");
async.map(
searcharticles,
async function (searcharticle) {
let cacheKey = `Blog:` + uuidv4();
await client.set(cacheKey, JSON.stringify(searcharticle));
return searcharticles;
},
function (err, searcharticles) {
if (err) throw err;
res.status(200).json({ searcharticles });
}
);
}
} catch (err) {
res.status(401).json({ message: "hata durumu oluştu" });
}
};
infinity scroll react code
export const SearchPost = (query, pageNumber) => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [blogs, setBlogs] = useState([]);
const [hasMore, setHasMore] = useState(false);
const [userInfo, setuserInfo] = useState();
useEffect(() => {
setBlogs([]);
}, [query]);
useEffect(() => {
setLoading(true);
setError(false);
let cancel;
axios({
method: "GET",
url: `/api/search`,
params: { q: query, page: pageNumber },
withCredentials: true,
cancelToken: new axios.CancelToken((c) => (cancel = c)),
})
.then((res) => {
console.log(res.data);
setBlogs((prevBlog) => {
return [
...new Set([...prevBlog, ...res.data.searcharticles.map((b) => b)]),
];
});
setHasMore(res.data.searcharticles.length);
setLoading(false);
setuserInfo(res.data.userInfo);
})
.catch((err) => {
if (axios.isCancel(err)) return;
setError(true);
});
return () => cancel();
}, [query, pageNumber]);
return { loading, error, blogs, hasMore, userInfo };
};
const [query, setQuery] = useState("");
const [pageNumber, setPageNumber] = useState(1);
const { ısAuthenticated } = useContext(AuthContext);
const { blogs, hasMore, loading } = SearchPost(query, pageNumber);
const observer = useRef();
const lastBlogElementRef = useCallback(
(node) => {
if (loading) return;
if (observer.current) observer.current.disconnect();
observer.current = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting && hasMore) {
//burda verıyı gecıp gecmedıgını kontrol etmelıyız
setPageNumber((prevPageNumber) => prevPageNumber + 1);
}
});
if (node) observer.current.observe(node);
},
[loading, hasMore]
);
function handleSearch(e) {
setQuery(e.target.value);
setPageNumber(1);
}
I'm writing for those who encounter this problem, you don't need to do a for loop. You can do this by typing the number of pages into the key. The edited code is below.
const searchpost = async (req, res) => {
let perpage = 3;
const value = req.query.q;
const pageNumber = req.query.page;
const query = `Blog:` + "/" + pageNumber;
try {
let redisPosts = await client.get(query);
if (redisPosts) {
redisPosts = JSON.parse(redisPosts);
res.status(200).json({ searcharticles: redisPosts });
} else {
const searcharticles = await Blog.find({
$or: [
{ title: { $regex: value, $options: "i" } },
{ tag: { $regex: value, $options: "i" } },
{ Subtitle: { $regex: value, $options: "i" } },
],
})
.skip((pageNumber - 1) * perpage)
.limit(perpage)
.populate("authorId");
let cacheKey = query;
await client.set(cacheKey, JSON.stringify(searcharticles));
res.status(200).json({ searcharticles });
}
} catch (err) {
res.status(401).json({ message: "hata durumu oluştu" });
}
};

SignalR connect setup in react- using useEffects

I'm using "#microsoft/signalr": "^6.0.5", and trying to set up a connection.
It is able to connect with the backend, but I am not sure if my setup looks OK for when the connection fails.
Specifically, I am wondering if the last useEffect is correctly written (the placement of the onClose clause)
useEffect(() => {
const newConnection = new HubConnectionBuilder()
.withUrl(
"https://localhost:3000/workorderHub",
{ accessTokenFactory: () => token, withCredentials: false }
)
.configureLogging(LogLevel.Information)
.withAutomaticReconnect()
.build();
setConnection(newConnection);
}, []);
useEffect(() => {
async function start() {
if (connection) {
try {
connection
.start()
.then(() => {
connection.invoke("SubscribeToProject", projectId); // calling hub method from the client
})
.catch((err) => {
console.error(err.toString());
});
connection.on(
"OperationUpdated",
(projectId, operationId, operation) => {
// function called from the backend Hub
actions.updateSyncedOperation({ operationId, operation });
}
);
} catch (err) {
console.log({ err });
setTimeout(start, 5000);
}
} else {
connection.onclose(async () => {
await start();
});
}
}
start();
}, [connection]);
For React 18 with the new strictMode behaviour i do the following.
It only creates one connection without any errors and it seems to cleanup properly during strictmode behaviour.
export const useLiveUpdates = () => {
const [connectionRef, setConnection] = useState < HubConnection > ();
function createHubConnection() {
const con = new HubConnectionBuilder()
.withUrl(`${EnvService.getUrlHub('url')}`, {
accessTokenFactory: () => AuthService.getToken(),
})
.withAutomaticReconnect()
.build();
setConnection(con);
}
useEffect(() => {
createHubConnection();
}, []);
useEffect(() => {
if (connectionRef) {
try {
connectionRef
.start()
.then(() => {
connectionRef.on('message', () => { ...
});
})
.catch((err) => {
logger.error(`Error: ${err}`);
});
} catch (error) {
logger.error(error as Error);
}
}
return () => {
connectionRef ? .stop();
};
}, [connectionRef]);
};

useEffect is not being called when dependency is changed

loadMoreMessages this is being called when the scrollTop gets to 0. and calling setScrollPosition but the useEffect is not being called.
setMessages is working fine
const [scrollPosition, setScrollposition] = useState('')
const { messages, setMessages } = useMessages()
let getMessages = ({onSuccess, onError, finaly = f => f}) => {
socket.emit('get:messages', (err, respo) => {
if(err) {
onError(err)
}
else {
console.log('respo ', respo)
else {
onSuccess(respo)
}
}
})
}
let loadMoreMessages = () => {
getMessages({
onError: err => console.log(err),
onSuccess: data => {
setMessages({
type: 'update',
data
})
console.log('messages updated') // the code dose reach here
setScrollposition('update')
}
})
}
useEffect(() => {
console.log(scrollPosition)
}, [scrollPosition])
might you can do this
useEffect(()=>{
if(scrollPosition === 'something'){
loadMoreMessages();
}
},[scrollPosition])

React native - React Hook useEffect has a missing dependency:'getAllPost'. Either include it or remove the dependency array.",

I am new in react native and try to call two api from useEffect but it give me this error every time React Hook useEffect has a missing dependency: 'getAllPost'. Either include it or remove the dependency array.
Here is my code
export default function Home({navigation}) {
const [arrCat, setArrCat] = useState([]);
const [arrPost, setArrPost] = useState([]);
const [isLoading, setLoding] = useState(false);
function getAllCategory() {
setLoding(true);
let apiResponse = ApiManager.GET('category/all', [], 'GET');
apiResponse
.then(response => {
let responseJson = response[1];
let status = response[0];
setLoding(false);
let message =
responseJson.message != null
? response.message
: 'Something went wrong';
if (status === 200) {
setArrCat([...responseJson.data]);
getAllPost();
}
setTimeout(function() {
if (message != null) {
Toast.showWithGravity(message, Toast.LONG, Toast.BOTTOM);
}
}, 120);
})
.catch(error => {
console.error(error);
Toast.showWithGravity(error, Toast.LONG, Toast.BOTTOM);
setTimeout(function() {
setLoding(false);
}, 60);
});
}
function getAllPost() {
GetLocation.getCurrentPosition({
enableHighAccuracy: true,
timeout: 15000,
})
.then(location => {
console.log(location);
const dictData = {
lat: '-37.81400200-33.865143', //location.latitude,
lang: '144.9546943', //location.longitude,
record_count: '0',
};
console.log(dictData);
let apiResponse = ApiManager.POST(
'post/getRecommendedPost',
dictData,
'POST',
);
apiResponse
.then(response => {
let responseJson = response[1];
let status = response[0];
if (status === 200) {
console.log(responseJson);
setArrPost(oldValue => [...oldValue, ...responseJson.data]);
console.log(arrPost);
} else {
// console.error(responseJson);
Toast.showWithGravity(
responseJson.message,
Toast.LONG,
Toast.BOTTOM,
);
}
})
.catch(error => {
// console.error(error);
Toast.showWithGravity(error.message, Toast.LONG, Toast.BOTTOM);
// setTimeout(function() {
// setLoding(false);
// }, 60);
});
})
.catch(error => {
// const {code, message} = error;
// console.warn(code, message);
Toast.showWithGravity(error.message, Toast.LONG, Toast.BOTTOM);
});
}
useEffect(() => {
console.log('Home screen mounted');
getAllCategory();
// getAllPost();
}, []);
return ( ....)
}

Resources