i use redux toolkit with react native and mongodb (mongoose)
i delete item and it successfully deleted from db
but not in client and need to reload page
todoSlice :
import {createSlice} from '#reduxjs/toolkit';
export const todoSlice = createSlice({
name: 'todos',
initialState: {
todos: [],
pending: null,
error: null,
},
reducers: {
deleteTodo: (state, action) => {
return state
},
},
});
export const {deleteTodo} = todoSlice.actions;
export default todoSlice.reducer;
apiCall:
import axios from 'axios';
import {deleteTodo} from './todoSlice';
export const deleteOneTodo = async (id, dispatch) => {
try {
await axios.delete(`http://10.0.2.2:5000/todos/${id}`);
dispatch(deleteTodo());
} catch (err) {
console.log(err);
}
};
main :
const {todo} = useSelector(state => state);
const dispatch = useDispatch();
const {todos} = todo;
useEffect(() => {
getTodos(dispatch);
}, []);
const handleDelete = id => {
deleteOneTodo(id, dispatch);
};
you have to implement deleteTodo inside your todoSlice in order to remove the deleted id from your local state,
...
export const todoSlice = createSlice({
name: 'todos',
initialState: {
todos: [],
pending: null,
error: null,
},
reducers: {
deleteTodo: (state, action) => {
return state.filter((todo)=>todo.id!==action.payload.id);
},
},
});
...
and of course you have to pass the payload with the id of the todo you want to remove
export const deleteOneTodo = async (id, dispatch) => {
try {
await axios.delete(`http://10.0.2.2:5000/todos/${id}`);
dispatch(deleteTodo({id:id}));
} catch (err) {
console.log(err);
}
};
if you still have doubts you can follow this tutorial: https://www.youtube.com/watch?v=fiesH6WU63I
i just call 'getTodos' inside 'deleteOneTodo'
and delete 'deleteTodo' from reducer
i hope its a good practice
export const deleteOneTodo = async (id, dispatch) => {
try {
await axios.delete(`http://10.0.2.2:5000/todos/${id}`);
// i add this line =>
getTodos(dispatch);
} catch (err) {
console.log(err);
}
};
Related
Somehow I when I make an API call using Prisma I can access only the default state:
import dbClient from '~/server/utils';
import { useTextStore } from '~/pinia/text'
export default defineEventHandler(async (event) => {
const { id } = event.context.params
const text = useTextStore()
const updatedText = await dbClient.opus.update({
where: {
id: parseInt(id),
},
data: {
content: text.content
},
});
return {
statusCode: 200,
body: text.content
}
})
Here's the Pinia store code:
import { defineStore } from 'pinia'
export const useTextStore = defineStore({
id: 'text',
state: () => {
return {
editor:'Введите текст',
}
},
actions: {
updateText(newContent) {
this.editor = newContent
}
},
getters: {
content: state => state.editor,
},
})
The state changes are shared across components and pages but can't get through to the eventHandler. Is it Nuxt 3 or some other mistake I should look into?
My problem is that initialState from slice.js not changing, when I console.log store(using UseSelector) I see that state.list empty and did not changed.I'm trying to catch data from GET endpoint, endpoint is working.
store.js
import { configureStore } from '#reduxjs/toolkit';
import shopReducer from '../connection/shopSlice';
export const store = configureStore({
reducer: {
shop: shopReducer,
},
devTools: true
});
slice.js
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit';
import axios from 'axios';
export const getProducts = createAsyncThunk(
'shop/getProducts',
async () => {
const response = await axios.get('http://localhost:3000/products');
return response.data;
}
);
export const listOfProducts = createSlice({
name: 'shop',
initialState: {
list: [],
status: 'idle',
error: null,
},
reducers: {
addProduct: {
reducer: (state, action) => {
state.list.push(action.payload);
},
prepare(value) {
return {
payload: {
key: value.id,
value: value,
},
};
},
},
},
extraReducers: {
[getProducts.pending]: (state, action) => {
state.status = 'loading';
},
[getProducts.fulfilled]: (state, action) => {
state.status = 'succeeded';
state.list.push(...action.payload);
},
[getProducts.rejected]: (state, action) => {
state.status = 'failed';
state.error = action.error.message;
},
},
});
export const { addProduct } = listOfProducts.actions;
export default listOfProducts.reducer;
component with console.log
import React from 'react';
import common from './common.module.scss';
import shopCards from './shopCards.module.scss';
import { useSelector } from "react-redux";
const ShopCards = () => {
console.log(useSelector(state=>state))
return (
<div>
</div>
);
};
export default ShopCards;
The issue is that you are not dispatching the getProducts at all, you should dispatch this action and get the state with useSelector(state => state.shop) to select the proper reducer state. Try to change your code to the following:
import React from 'react';
import common from './common.module.scss';
import shopCards from './shopCards.module.scss';
// Don't forget to change the path
import { getProducts } from './path/to/reducer'
import { useSelector, useDispatch } from "react-redux";
import { useEffect } from "react";
const ShopCards = () => {
const products = useSelector((state) => {state.shop});
useEffect(() => {
// dispatch the action on first render
useDispatch(getProducts());
}, []);
useEffect(() => {
// print the products if the fetch to backend was made successfully
console.log(products);
}, [products]);
return (
<div>
</div>
);
};
export default ShopCards;
Other thing, in your createAsyncThunk you are returning response.data, so to fulfill properly the state, your api response should looks like this:
{
// you must return a JSON with data key who has an array of your products
// the content of product was just an example, so ignore it
data: [{id: 1, product: "foo"}]
}
So, I have looked through the docs and answers on here and I'm still needing some help:
index.tsx
const getInfiniteArticles = ({ pageParams = 0 }) => {
const res = await axios.get('/api/articles', { params: { page: pageParams } });
return res.data;
}
api/articles.ts
const getArticles = async (req: NextApiRequest, res: NextApiResponse) => {
try {
const { page } = req.query;
const pageNum = Number(page);
const data = await NewsService.getArticles(getRange(pageNum));
return res.status(200).json({
data,
previousPage: pageNum > 0 ? (pageNum - 1) : null,
nextPage: pageNum + 1,
});
} catch (err) {
res.json(err);
res.status(405).end();
}
};
export default getArticles;
index.tsx
const { data: articlePages, fetchNextPage } = useInfiniteQuery(
'infinite-articles',
getInfiniteArticles,
{
getNextPageParam: (lastPage, allGroups) => {
console.log('lastPage: ', lastPage);
console.log('allGroups: ', allGroups);
return lastPage.nextPage;
}
});
const handleLoadMore = () => {
fetchNextPage();
};
console after clicking next page:
lastPage: { data: Array(50), previousPage: null, nextPage: 1}
allGroups: [
{ data: Array(50), previousPage: null, nextPage: 1},
{ data: Array(50), previousPage: null, nextPage: 1},
]
Any help on why I'm getting the same groups is appreciated! :)
So, it turns out my structure wasn't correct
const {
fetchNextPage,
fetchPreviousPage,
hasNextPage,
hasPreviousPage,
isFetchingNextPage,
isFetchingPreviousPage,
...result
} = useInfiniteQuery(queryKey, ({ pageParam = 1 }) => fetchPage(pageParam), {
...options,
getNextPageParam: (lastPage, allPages) => lastPage.nextCursor,
getPreviousPageParam: (firstPage, allPages) => firstPage.prevCursor,
})
queryFn: (context: QueryFunctionContext) => Promise<TData>
The queryFn is supposed to be a synchronous function that returns a Promise
I was either passing an async function or I was returning the TData not a promise.
updated and working:
const getInfiniteArticles = ({ pageParam = 0 }) => axios.get('/api/articles', { params: { page: pageParam } });
const { data: articlePages, fetchNextPage } = useInfiniteQuery('articles', getInfiniteArticles, {
getNextPageParam: (lastPage, pages) => {
// the returned axios response
return lastPage.data.nextPage;
}
});
Reference Page
I just started coding and I tried to delete a post through my mongoDB API. The code that I used is pretty basic, my API requests all go through a reducer which is set up pretty clear. But when I try to delete a post from my DB, I get the error ''[Unhandled promise rejection: Error: Request failed with status code 404]''. Did I do something wrong here or is this a mongoDB problem? I've included the necessary code.
This is my reducer request:
const deleteWorkout = (dispatch) => {
return async (_id) => {
await trackerApi.delete(`/workouts/${_id}`);
dispatch({ type: "delete_workout", payload: _id });
};
};
This is my complete reducer code:
import createWorkoutDataContext from "./createWorkoutDataContext";
import trackerApi from "../api/tracker";
const workoutReducer = (workouts, action) => {
switch (action.type) {
case "get_workouts":
return action.payload;
case "add_workout":
return [
...workouts,
{
title: action.payload.title,
exercises: action.payload.exercises,
},
];
case "edit_workout":
return workouts.map((Workout) => {
return Workout._id === action.payload.id ? action.payload : Workout;
});
case "delete_workout":
return workouts.filter((Workout) => Workout._id !== action.payload);
default:
return workouts;
}
};
const getWorkouts = (dispatch) => async () => {
const response = await trackerApi.get("/workouts");
dispatch({ type: "get_workouts", payload: response.data });
};
const addWorkout = (dispatch) => {
return async (title, exercises, callback) => {
await trackerApi.post("/workouts", { title, exercises });
if (callback) {
callback();
}
};
};
const editWorkout = (dispatch) => {
return async (title, exercises, _id, callback) => {
await trackerApi.put(`/workouts/${_id}`, { title, exercises });
dispatch({ type: "edit_workout", payload: { _id, title, exercises } });
if (callback) {
callback();
}
};
};
const deleteWorkout = (dispatch) => {
return async (_id) => {
await trackerApi.delete(`/workouts/${_id}`);
dispatch({ type: "delete_workout", payload: _id });
};
};
export const { Context, Provider } = createWorkoutDataContext(
workoutReducer,
{ addWorkout, getWorkouts, deleteWorkout },
[]
);
This is my code where I use the delete function:
const WorkoutListScreen = () => {
const { workouts, getWorkouts, deleteWorkout } = useContext(WorkoutContext);
return (
<View style={styles.container}>
<Text style={styles.pageTitle}>My Workouts</Text>
<NavigationEvents onWillFocus={getWorkouts} />
<FlatList
data={workouts}
keyExtractor={(item) => item._id}
renderItem={({ item }) => {
return (
<TouchableOpacity
onPress={() => navigate("WorkoutDetail", { _id: item._id })}
>
<View style={styles.row}>
<Text style={styles.title}>{item.title}</Text>
<TouchableOpacity onPress={() => deleteWorkout(item._id)}>
<Ionicons style={styles.deleteIcon} name="trash-outline" />
</TouchableOpacity>
</View>
</TouchableOpacity>
);
}}
/>
I simply included the deleteWorkout function in my TouchableOpacity, so I suppose that the problem lies within the reducer code?
here is the error I keep getting:
[Unhandled promise rejection: Error: Request failed with status code 404]
at node_modules\axios\lib\core\createError.js:16:14 in createError
at node_modules\axios\lib\core\settle.js:17:22 in settle
at node_modules\axios\lib\adapters\xhr.js:66:12 in onloadend
at node_modules\event-target-shim\dist\event-target-shim.js:818:20 in EventTarget.prototype.dispatchEvent
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:614:6 in setReadyState
at node_modules\react-native\Libraries\Network\XMLHttpRequest.js:396:6 in __didCompleteResponse
at node_modules\react-native\Libraries\vendor\emitter\_EventEmitter.js:135:10 in EventEmitter#emit
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:414:4 in __callFunction
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:113:6 in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:365:10 in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:112:4 in callFunctionReturnFlushedQueue
This is what the objects in my databse look like (through Postman):
{
"userId": "615e06f36ce5e5f1a69c675e",
"title": "Defaults test",
"exercises": [
{
"exerciseTitle": "shadowboxing",
"exerciseProps": {
"time": 0,
"sets": 0,
"reps": 0
},
"_id": "6184c6fa685291fb44778df7"
},
{
"exerciseTitle": "bag workout",
"exerciseProps": {
"time": 4,
"sets": 0,
"reps": 12
},
"_id": "6184c6fa685291fb44778df8"
},
{
"exerciseTitle": "Exercise",
"exerciseProps": {
"time": 4,
"sets": 3,
"reps": 12
},
"_id": "6184c6fa685291fb44778df9"
}
],
"_id": "6184c6fa685291fb44778df6",
"__v": 0
}
I'm gratefull for your help!
I'm trying to get Gifted Chat implemented in a realtime fashion with socket.io but I'm having issues. I'm able to get socket.io to connect, the message to be emitted, but it isn't showing up in real time when I have an android emulator and an iPhone simulator both running the app.
server.js
const express = require("express");
const http = require("http");
const app = express();
const server = http.createServer(app);
// Attempt at Socket.io implementation
const socket = require('socket.io')
const io = socket(server)
const bodyParser = require('body-parser');
const Message = require("./models/message");
const SportsMessage = require('./models/sportsMessage')
const GamerMessage = require('./models/gamerMessage')
const mongoose = require('mongoose');
// MongoDB connection
mongoose.connect(
'mongodb+srv://yada:yada#cluster0.kt5oq.mongodb.net/Chatty?retryWrites=true&w=majority', {
useNewUrlParser: true,
useUnifiedTopology: true
}).then(() => {
console.log('Connected to the database!')
}).catch(() => {
console.log('Connection failed oh noooooo!')
});
// Parse the request body as JSON
app.use(bodyParser.json());
// GET messages, don't change these bro
app.get("/api/messages", (req, res) => {
Message.find({}).exec((err, messages) => {
if(err) {
res.send(err).status(500);
} else {
res.send(messages).status(200);
}
});
});
app.get("/api/sportsMessages", (req, res) => {
SportsMessage.find({}).exec((err, messages) => {
if(err) {
res.send(err).status(500);
} else {
res.send(messages).status(200);
}
});
});
app.get("/api/gamerMessages", (req, res) => {
GamerMessage.find({}).exec((err, messages) => {
if(err) {
res.send(err).status(500);
} else {
res.send(messages).status(200);
}
});
});
// POST messages
app.post('/api/messages', (req, res) => {
Message.create(req.body).then((message) => {
res.send(message).status(200);
}).catch((err) => {
console.log(err);
res.send(err).status(500);
});
});
app.post('/api/sportsMessages', (req, res) => {
SportsMessage.create(req.body).then((message) => {
res.send(message).status(200);
}).catch((err) => {
console.log(err);
res.send(err).status(500);
});
});
app.post('/api/gamerMessages', (req, res) => {
GamerMessage.create(req.body).then((message) => {
res.send(message).status(200);
}).catch((err) => {
console.log(err);
res.send(err).status(500);
});
});
// Socket.io connection
io.on('connection', socket => {
socket.emit('your id', socket.id)
socket.on('send message', body => {
console.log(body)
io.emit('send message', body)
})
console.log("connected to dat socket boiii")
})
server.listen(8000, () => console.log("server is running on port 8000"));
Chat Screen
import React, { useState, useEffect, useContext, useRef } from 'react'
import { View, Text, Button, StyleSheet } from 'react-native'
import io from 'socket.io-client'
import useMessages from '../hooks/useMessages'
import { Context as UserContext } from '../context/UserContext'
import { GiftedChat as GChat } from 'react-native-gifted-chat'
const GeneralChat = () => {
const [messages, ids, getMessages, randomId, setMessages] = useMessages()
const { state: { username } } = useContext(UserContext)
const socketRef = useRef()
socketRef.current = io('{MyIP}')
useEffect(() => {
getMessages()
randomId()
const socket = io('{MyIP}')
socket.on('your id', id => {
console.log(id)
})
}, [])
const onSend = (message) => {
let userObject = message[0].user
let txt = message[0].text
console.log(message)
setMessages(previousMessages => GChat.append(previousMessages, message))
const messageObject = {
text: txt,
user: userObject
}
socketRef.current.emit('send message', messageObject)
fetch("{MyIP}/api/messages", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(messageObject)
}).then((res) => {
return res.json();
}).catch((err) => {
console.log(err);
});
}
return (
<GChat
// isLoadingEarlier
scrollToBottom
infiniteScroll
loadEarlier
alwaysShowSend
renderUsernameOnMessage
inverted={true}
showUserAvatar
messages={messages}
onSend={message => onSend(message)}
user={{
_id: ids,
name: username,
avatar: 'https://placeimg.com/140/140/any'
}}
/>
)
}
GeneralChat.navigationOptions = () => {
return {
title: 'General Chat',
}
}
const styles = StyleSheet.create({
})
export default GeneralChat