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();
};
Related
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}`);
};
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" });
}
};
I have an Axios get request I'd like to cancel upon an event but it doesn't seem to work.
// user.services.js
searchFAQS(query) {
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
source.cancel('Operation cancelled by user')
return axios.get(
authHeader.getApiUrl() + '/api/v1/search_faqs',
{
cancelToken: source.token,
params: {
query: query
}
}
)
}
// ClassComponent
onChangeQuery = (e) => {
if (e.target.value === "") {
this.setState({
fFaq: "",
query: e.target.value
})
} else {
UserServices.searchFAQS().cancel()
this.setState({query: e.target.value},
() => UserServices.searchFAQS(this.state.query)
.then(resp => {
this.setState({
fFaq: resp.data,
fGroups: resp.data.map(f => f.group).filter((value, index, self) => self.indexOf(value) === index)
})
}))
}
}
I read the cancellation part for the Axios documentation, which is what led me to the attempt above, but it doesn't seem to be canceling after observing the requests from developer tools.
searchFAQS(query) {
const CancelToken = axios.CancelToken;
.....
new CancelToken is creating on every searchFAQS call, so it will not get cancel because everytime it's a new token
change as below
let token = null; // define cancel token outside the search fn, then it will not recreate on every call
searchFAQS(query) {
if (token !== null) {
token();
}
...
const { CancelToken } = axios;
...
return axios.get(
authHeader.getApiUrl() + '/api/v1/search_faqs',
{
cancelToken: new CancelToken(function executor(cancellableFn) {
token = cancellableFn;
}),
params: {
query: query
}
}
....
On my understanding you solution should looks like this:
// user.services.js
async searchFAQS(query, source = '') {
const search = axios.get(
authHeader.getApiUrl() + '/api/v1/search_faqs',
{
cancelToken: source.token,
params: {
query: query
}
}
);
if (source /* change to your needs, actualy it cancels all requests */) {
source.cancel('Ok, its just canceled!');
}
return await search.data;
}
// ClassComponent
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
onChangeQuery = (e) => {
if (e.target.value === "") {
this.setState({
fFaq: "",
query: e.target.value
})
} else {
UserServices.searchFAQS("", source)
this.setState({query: e.target.value},
() => UserServices.searchFAQS(this.state.query, source)
.then(resp => {
this.setState({
fFaq: resp.data,
fGroups: resp.data.map(f => f.group).filter((value, index, self) => self.indexOf(value) === index)
})
}))
}
}
I am trying to use a http hook in another component to send a get request. The post request is working fine. But when I try a get request I just get back 'true' when I console log my result. When I send the same get request in postman I get the correct data back, so it isn't a backend problem.
The hook:
import { useState, useCallback, useRef, useEffect } from "react";
export const useHttpClient = () => {
const [isLoading, setIsLoading] = useState(false);
const [errors, setErrors] = useState();
const [success, setSuccess] = useState(false);
const activeHttpRequests = useRef([]);
const sendRequest = useCallback(
async (url, method = "GET", body = null, headers = {}) => {
setIsLoading(true);
const httpAbortController = new AbortController();
activeHttpRequests.current.push(httpAbortController);
try {
setErrors();
setSuccess(false);
const response = await fetch(url, {
method: method,
body: body,
headers: headers,
signal: httpAbortController.signal,
});
const responseData = await response.json();
activeHttpRequests.current = activeHttpRequests.current.filter(
(reqCtrl) => reqCtrl !== httpAbortController
);
if (response.status !== 200) {
setErrors(responseData);
return responseData;
} else {
setSuccess(true);
return true;
}
} catch (err) {
//setErrors(err.message);
setErrors([
"There was an error submitting your form, please try again later.",
]);
setIsLoading(false);
throw err;
}
},
[]
);
//useEffect can also be used for cleanup
useEffect(() => {
return () => {
activeHttpRequests.current.forEach((AbortController) =>
AbortController.abort()
);
};
}, []);
return { isLoading, errors, sendRequest, success };
};
The server call:
useEffect(() => {
const fetchFaq = async () => {
try {
const responseData = await sendRequest(
"http://localhost:8000/api/myEndpoint"
);
console.log(responseData);
setLoadedFaq(responseData);
} catch (err) {}
};
fetchFaq();
}, [sendRequest]);
Your hook returns true if it gets a 200 response code:
if (response.status !== 200) {
setErrors(responseData);
return responseData;
} else {
setSuccess(true);
return true;
}
It only returns responseData if it gets a non-200 code. Just return the data from the hook..
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 ( ....)
}