How does infinite scroll work in case of caching redis - reactjs

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

Related

How to move document up and down within collection MongoDB

I have a simple notes app, where I made it possible for adding, deleting a single note and changing importance. But I can't figure out how to make it moving single note up or down; change the order of notes. My approach is to reorder array of current notes and then somehow post or replace existing collection in my database. But I can't find right tool for this.
I'm using React, Node.js and MongoDB through Mongoose.
P.S: I googled it, and found nothing relevant to this. But I think it's a simple operation and there should be a function for this in MongoDB.
Here is code from my backend index.js file:
app.post('/api/notes', (request, response) => {
const body = request.body;
if (body.content === undefined) {
return response.status(400).json({
error: 'content missing',
});
}
const note = new Note({
content: body.content,
important: body.important || false,
date: new Date(),
});
note.save().then((savedNote) => {
response.json(savedNote);
});
});
app.get('/api/notes/', (request, response) => {
Note.find({}).then((notes) => {
response.json(notes);
});
});
app.get('/api/notes/:id', (request, response, next) => {
Note.findById(request.params.id)
.then((note) => {
if (note) {
response.json(note);
} else {
response.status(404).end();
}
})
.catch((error) => next(error));
});
app.delete('/api/notes/:id', (request, response, next) => {
Note.findByIdAndRemove(request.params.id)
.then((result) => {
response.status(204).end();
})
.catch((error) => next(error));
});
app.put('/api/notes/:id', (request, response, next) => {
const body = request.body;
const note = {
content: body.content,
important: body.important,
};
Note.findByIdAndUpdate(request.params.id, note, { new: true })
.then((updatedNote) => {
response.json(updatedNote);
})
.catch((error) => next(error));
});
Code snippet from frontend:
const App = () => {
const [notes, setNotes] = useState([]);
const [newNote, setNewNote] = useState('');
const [showAll, setShowAll] = useState(true);
const [errorMessage, setErrorMessage] = useState(null);
useEffect(() => {
noteService.getAll().then((initialNotes) => {
setNotes(initialNotes);
});
}, []);
const addNote = (event) => {
event.preventDefault();
const noteObject = {
content: newNote,
date: new Date().toISOString(),
important: Math.random() > 0.5,
id: notes.length + 1,
};
noteService.create(noteObject).then((returnedNote) => {
setNotes(notes.concat(returnedNote));
setNewNote('');
});
};
const handleNoteChange = (event) => {
setNewNote(event.target.value);
};
const toggleImportanceOf = (id) => {
const note = notes.find((n) => n.id === id);
const changedNote = { ...note, important: !note.important };
console.log('Changed');
noteService
.update(id, changedNote)
.then((returnedNote) => {
console.log(returnedNote);
setNotes(notes.map((note) => (note.id !== id ? note : returnedNote)));
})
.catch((error) => {
setErrorMessage(
`Note '${note.content}' was already removed from server`
);
setTimeout(() => {
setErrorMessage(null);
}, 5000);
setNotes(notes.filter((n) => n.id !== id));
});
};
const delNote = (id) => {
window.confirm(`Delete this note?`);
noteService.del(id);
noteService.getAll().then((initialNotes) => {
setNotes(initialNotes);
});
};
const moveUp = (id) => {
const idN = notes.findIndex((n) => n.id === id);
console.log(idN);
//that's where I reorder my current notes(moving up)
let updated = [...notes];
updated.splice(
idN === 0 ? updated.length - 1 : idN - 1,
0,
updated.splice(idN, 1)[0]
);
};
const notesToShow = showAll ? notes : notes.filter((note) => note.important);
And finally code from api (noteService in the code above):
const getAll = () => {
let request = axios.get(baseUrl);
return request.then((res) => res.data);
};
const create = (newObject) => {
const request = axios.post(baseUrl, newObject);
return request.then((res) => res.data);
};
const update = (id, newObject) => {
const request = axios.put(`${baseUrl}/${id}`, newObject);
return request.then((res) => res.data);
};
const del = (id) => {
axios.delete(`${baseUrl}/${id}`);
};

Socket works the for a few seconds then fails

I've managed to establish a connection using socket. It works great for the first few seconds after that it runs super slow takes like almost 2-3 mins to complete a request. And then it produces this error continuously. The app doesn't crash it just runs slowly with the error displaying countless times.
Firefox can’t establish a connection to the server at ws://localhost:5000/socket.io/?EIO=4&transport=websocket&sid=9S6kqHJdHHXQgrobAAHp..
Error on console.
Main.js
function Home(props) {
const [Username , setUsername] = useState("")
const [SearchedData, setSearchedData] = useState()
const [Data, setData] = useState()
const socket = io('http://localhost:5000')
React.useEffect(() => {
// socket.current = io('http://localhost:5000')
socket.emit("content","yada")
socket.on("get-data", data => {
setData(data)
})
})
function NavBar(props){
const handleClick = (e) => {
const {id} = e.target
if(id === "Post-btn"){
if(Content.length > 0){
let data = {
Username: "yada", Content
}
props.socket.emit("store-data", data)
}
}
return(
Tags....
)}
function Content (props) {
const onLike = (e) => {
const { id } = e.target.dataset
const data = {
username: "yada",
id : id
}
// console.log(data)
props.socket.emit("like", data)
}
return(
Tags.....
)
}
server.js
mongoose.connect(process.env.MongoDB,
{ useNewUrlParser: true, useUnifiedTopology: true }).then(() => {
console.log("Database Connected")
}).catch(err => {
console.log(err)
});
const server = app.listen(process.env.Port, () => {
console.log("Connected on " + process.env.Port)
})
const io = socket(server, {
cors:{
origin: "http://localhost:3000",
credential: true,
}
})
let cuid;
io.on("connection", (socket) => {
socket.on("content", username => {
Comments.find({},(err, data) => {
if(!err)
socket.emit("get-data", data)
})
})
socket.on("store-data", data => {
const {Username, Content} = data
const newdata = new Comments({
userName: Username,
content: Content,
createdAt: new Date().toDateString(),
replies: []
})
newdata.save().then(data => {
for(const d in data)
if(d === "_id"){
Users.findOneAndUpdate({username: Username}, {$push: {UserContent: data[d]}}, {new: true}, (err, save) => {
if(err)
console.log(err)
else
console.log(save)
})
}
})
})
socket.on("like", data => {
const {username, id} = data
Users.findOne({username:username}, (err, data) => {
if(!err){
cuid = data['id']
console.log(cuid)
Comments.findByIdAndUpdate(id, {$set: {score: data['_id']}}, {upsert: true}, (err, d) => {
if(!err){
console.log(d)
}
})
}
})
})
})
Looking at the code provided, I noticed there is an useEffect without params. This may be causing a loop until the application crashes.
React.useEffect(() => {
// socket.current = io('http://localhost:5000')
socket.emit("content","yada")
socket.on("get-data", data => {
setData(data)
})
socket.on("Updated", data => {
setData(data)
})
}, []); <- this is missing
This empty array indicates that the content inside the useEffect will only run once.
More about this https://reactjs.org/docs/hooks-intro.html

How can I update updateNotes first then getNotes?

Here it's logging first getNotes then updateNotes
is there a way to first updateNotes then getNotes? Because when I edit and click the left Arrow icon it's not updating changes unless I refresh the page.
Here is the code from NotesPage.js
const NotesPage = () => {
const [notes, setNotes] = useState([]);
useEffect(() => {
getNotes();
console.log('Log from getNotes');
}, [])
const getNotes = async () => {
const response = await fetch("http://localhost:5000/notes");
const data = await response.json()
setNotes(data)
}
and here is the code from NotePage.js
function NotePage({ match, history }) {
const noteId = match.params.id;
const [note, setNote] = useState(null);
useEffect(() => {
getNote();
console.log("Log from getNote");
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [noteId]);
const getNote = async () => {
if (noteId === 'new') return
const response = await fetch(`http://localhost:5000/notes/${noteId}`);
const data = await response.json();
setNote(data);
};
const updateNote = async () => {
await fetch(`http://localhost:5000/notes/${noteId}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ ...note, "updated": new Date() }),
});
console.log("Log from updateNote");
};
const handeSubmit = () => {
if (noteId !== "new" && !note.body) {
deleteNote();
} else if (noteId !== "new") {
updateNote();
} else if (noteId === 'new' && note !== null) {
createNote()
}
history.push("/");
};
Try getNotes after doing all other actions
Like so:
const handeSubmit = async () => {
if (noteId !== "new" && !note.body) {
await deleteNote();
} else if (noteId !== "new") {
await updateNote();
} else if (noteId === "new" && note !== null) {
await createNote();
}
getNote();
};

useState not triggers rerendering in websocket callback handler

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

React-Native Firebase Image upload Expo

I am trying to upload an image to firebase storage however I am getting the error object Object as shown below
Please may someone help me I have never uploaded an image to firebase and really need assistance . Any help what's so ever will be much appreciated. Thank you sooo much in advance!!!!!
This is my code. I've Initialized firebase as well as my image path postImage works as expected.
const handleSubmit = () => {
if (postImage !== undefined) {
const fileExtention = postImage[0].split('.').pop()
console.log(`EXT ${fileExtention}`)
const fileName = `${uniqid}.${fileExtention} `
const reference = firebase.storage().ref(`Posts/images/${fileName}`)
reference.put(postImage)
.on(
firebase.storage.TaskEvent.STATE_CHANGED,
snapshot => {
console.log(`snapshot ${snapshot.state}`)
console.log(`progress ${(snapshot.bytesTransferred / snapshot.totalBytes) * 100}`)
if (snapshot.state === firebase.storage.TaskState.SUCCESS) {
console.log('Success')
}
},
error => {
unsubscribe()
console.log("image upload failed" + error.toString())
},
() => {
firebase.storage()
.ref(`posts/images/${fileName}`)
.getDownloadURL()
.then((downloadUrl) => {
console.log(`file available at ${downloadUrl}`)
})
}
)
}
}
here a solution
const [image, setImage] = useState(null);
const [uploading, setUploading] = useState('')
useEffect(() => {
getPermission();
}, []);
const getPermission = async () => {
if (Platform.OS !== "web") {
const { status } =
await ImagePicker.requestMediaLibraryPermissionsAsync();
if (status !== "granted") {
alert("Sorry, we need camera roll permissions to make this work!");
}
}
};
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
if (!result.cancelled) {
setImage(result.uri);
}
};
const getPictureBlob = (uri) => {
// https://github.com/expo/expo/issues/2402#issuecomment-443726662
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", image, true);
xhr.send(null);
});
};
const uploadImageToBucket = async () => {
let blob;
try {
setUploading(true);
blob = await getPictureBlob(image);
const ref = await storage.ref().child(uuid.v4());
const snapshot = await ref.put(blob);
return await snapshot.ref.getDownloadURL();
} catch (e) {
alert(e.message);
} finally {
blob.close();
setUploading(false);
}
};

Resources