I have the below code, the problem is in the part where I am calling the RemoveProduct function in the map function:
function AddOrder() {
const d = new Date();
let text = d.toString();
const [addOrder] = useMutation(queries.ADD_ORDER);
const [editUser] = useMutation(queries.EDIT_USER_CART);
const [editProduct] = useMutation(queries.EDIT_PRODUCT);
function RemoveProduct (x) {
let getProd = useQuery(queries.GET_PRODUCTS_BY_ID, {
fetchPolicy: "network-only",
variables: {
_id : x._id
},
});
console.log(getProd.quantity)
console.log(x.quantity)
let a = getProd.quantity - x.quantity
console.log(a)
editProduct({
variables: {
_id : x._id,
quantity: a
},
});
return null;
}
const { currentUser } = useContext(AuthContext);
if (error) {
return <h1> error</h1>;
} else if (loading) {
return <h1> loading</h1>;
} else if (data && getUserOrders.data && currentUser && data.getUser.cart.length > 0) {
let newCart = [];
let total = 0;
for (let i = 0; i < data.getUser.cart.length; i++) {
total += data.getUser.cart[i].price * data.getUser.cart[i].quantity;
newCart.push({
orderedQuantity: data.getUser.cart[i].quantity,
_id: data.getUser.cart[i]._id,
name: data.getUser.cart[i].name,
image: data.getUser.cart[i].image,
price: data.getUser.cart[i].price,
});
}
newCart.map((x) => RemoveProduct(x))
editUser({
variables: {
id: currentUser.uid,
cart: [],
},
});
}
}
export default AddOrder;
I get the following error when I run this code:
Uncaught Error: Rendered more hooks than during the previous render.
How can I fix this? I tried to create a separate component for RemoveProducts and call in this function but that did not work either.
Only call hooks at the top level
Don't call hooks inside loops, conditions or nested functions
Always use hooks at the top level of your React function, before any
early returns
Only call hooks from React function components or from custom hooks.
I read this from the docs here
So try not to nest the function RemoveProduct or remove the hook called inside it
Related
I am getting the following error when I run myu application and click on a submit button,
React has detected a change in the order of Hooks called by SideBarItemTemplateWithData. This will lead to bugs and errors if not fixed. For more information, read the Rules of Hooks: https://reactjs.org/link/rules-of-hooks
Previous render Next render
------------------------------------------------------
1. useContext useContext
2. useMemo useState
My SideBarItemTemplateWithData,
RoomListRowProps): ReactElement {
const { sidebar } = useLayout();
let priority:any;
let userRoomId:any;
let data:any;
const href = roomCoordinator.getRouteLink(room.t, room) || '';
const title = roomCoordinator.getRoomName(room.t, room) || '';
if (room && room.v && room.v._id) {
userRoomId = room.v._id;
}
if (room && room.priorityId) {
data = useEndpoint('GET', `/v1/livechat/priorities/${room.priorityId}`);
}
if (data && data.value && data.value.name) {
priority = data.value.name.toLowerCase();
}
const {
lastMessage,
hideUnreadStatus,
hideMentionStatus,
unread = 0,
alert,
userMentions,
groupMentions,
tunread = [],
tunreadUser = [],
rid,
t: type,
cl,
} = room;
<SideBarItemTemplate
userId={userRoomId}
priority={priority}
is='a'
/>
I am getting the error when I run the above code but when I comment the following line it is working fine,
if (room && room.priorityId) {
data = useEndpoint('GET', `/v1/livechat/priorities/${room.priorityId}`);
}
The below line returns a promise,
useEndpoint('GET', `/v1/livechat/priorities/${room.priorityId}`);
Can anyone suggest me to how can I modify it o that the issue will be resolved. Thanks
useEndPoint code,
export const useEndpoint = <TMethod extends Method, TPath extends PathFor<TMethod>>(
method: TMethod,
path: TPath,
): EndpointFunction<TMethod, MatchPathPattern<TPath>> => {
const { callEndpoint } = useContext(ServerContext);
return useCallback((params: any) => callEndpoint(method,
path, params), [callEndpoint, path, method]);
};
How to use useEndPoint,
const sendEmailCode = useEndpoint('POST', '/v1/users.2fa.sendEmailCode');
await sendEmailCode({ emailOrUsername });
My Code,
const priorityData = useEndpoint('GET', `/v1/livechat/priorities/${room.priorityId}`);
if (room && room.v && room.v._id) {
userRoomId = room.v._id;
}
const onClickResendCode = async (): Promise<any> => {
try {
let priorityVal = '';
let data = await priorityData();
if (data && data.name) {
priorityVal = data.name.toLowerCase();
}
return priorityVal;
} catch (error) {
throw error;
}
};
priority = onClickResendCode();
Can anyone please suggest how can I modify the api call
The error is not about the promise, is about the order of the hook. In React you must keep the order of all your hook. You should not use your hook in a if or a loop.
This is the error.
if (room && room.priorityId) {
data = useEndpoint('GET', `/v1/livechat/priorities/${room.priorityId}`);
}
it should be
data = useEndpoint('GET', `/v1/livechat/priorities/${room.priorityId}`);
You can use if in the callEndpoint function, which is not a react hook.
I have useContext which save all loggedUsers in an array. Each user has few properties, one of them is messages array, which stores objects with two properties. I am using this context through custom hook inside of component, like so: const { loggedUsers, setLoggedUsers } = useUsers();. The context looks like this:
export const UsersProvider = ({ children }: Props) => {
const [loggedUsers, setLoggedUsers] = useState<any[]>([]);
const socket = useSocket();
const addUser = (user: any) => {
console.log(typeof loggedUsers);
const users: any[] = loggedUsers;
users.push(user);
setLoggedUsers(users);
};
const sortUsers = (users: any) => {
users.forEach((user: any) => {
user.self = user.userID === socket?.id;
});
let sorted = users.sort((a: any, b: any) => {
if (a.self) return -1;
if (b.self) return 1;
if (a.username < b.username) return -1;
return a.username > b.username ? 1 : 0;
});
setLoggedUsers(sorted);
};
return (
<UsersContext.Provider
value={{ loggedUsers, setLoggedUsers, addUser, sortUsers }}
>
{children}
</UsersContext.Provider>
);
};
User in array looks like this:
{userID: 'Cm6vG0udcV6vl7MEAAAB', userName: 'test123', messages: [{message: 'dsada', fromSelf: true}], self: false, connected: true}
I am updating the context/state like so, but it doesn't force rerender, so my messages between users are not shown. What could be the problem? If I console.log loggedUsers the messages are there, but they do not show up on DOM. If you need more code, let me know.
socket.on('private message', listenerMessage);
const listenerMessage = async (msgInfo: any) => {
console.log(msgInfo);
console.log(msgInfo.from);
const usersList = loggedUsers;
for (let i = 0; i < usersList.length; i++) {
const user = usersList[i];
if (user.userID === msgInfo.from) {
user.messages.push({
message: msgInfo.message,
fromSelf: false,
});
if (user !== state.userID) {
user.hasNewMessages = true;
}
console.log(loggedUsers, 'onprivatemessage');
setLoggedUsers(usersList);
break;
}
}
};
const onMessage = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
if (state.userName) {
socket?.emit('private-message', {
message: mess,
to: state.userID,
});
const usersList = loggedUsers;
for (let i = 0; i < usersList.length; i++) {
const user = usersList[i];
if (user.userID === state.userID) {
user.messages.push({ message: mess, fromSelf: true });
console.log(loggedUsers, 'onmessage');
}
}
setLoggedUsers(usersList);
}
setMess('');
};
You shouldn't mutate useState's state directly.
Clone it before:
const usersList = [...loggedUsers]
const usersList = loggedUsers.slice()
Here :
setLoggedUsers(usersList);
You are passing the same state array to setLoggedUsers. Cloning the state will solve this.
What you can do is this :
setLoggedUsers(prev=>{
const prevUserList = prev.slice()
//your for loop or anything
return prevUserList;
});
Also here :
const usersList = loggedUsers;
for (let i = 0; i < usersList.length; i++) {
const user = usersList[i];
if (user.userID === state.userID) {
user.messages.push({ message: mess, fromSelf: true });
console.log(loggedUsers, 'onmessage');
}
}
You never update usersList , i don't know if that is wanted.
you using const while you updating the objects.
try using let and not const.
const objects should not be changed.
setup() {
const { orders, orders_error, load_orders, profits } = getOrders()
load_orders()
console.log('ARRAY', profits)
let new_series = [{
name: 'series1',
data: profits.value
}]
return { new_series, orders, load_orders, orders_error, profits }
And this is the .js exported function:
import { ref } from 'vue'
import { projectFirestore, projectAuth } from '../firebase/config'
//import { ref } from '#vue/composition-api'
const getOrders = () => {
const user = projectAuth.currentUser.uid
let orders = ref([])
let profits = ref([])
let profit = 0
const orders_error = ref('')
const load_orders = async () => {
try {
projectFirestore.collection('users')
.doc(user)
.collection('orders')
.doc('845thfdkdnefnt4grirg')
.collection('profits')
.onSnapshot(async (snap) => {
// In this implementation we only expect one active or trialing subscription to exist.
let docs = snap.docs.map(doc => {
return { ...doc.data(), id: doc.id }
})
orders.value = docs
let last = 0
orders.value.forEach(element => {
console.log('ELEMENT', element.profit_cash)
profit = last + element.profit_cash
last = profit
profits.value.push(profit)
//orders.push(element.profit_cash)
})
//console.log('ARR', profits.value)
});
}
catch (err) {
orders_error.value = err.message
console.log(orders_error.value)
}
}
load_errors()
return { orders, orders_error, load_errors, profits }
}
export default getOrders
I'm able to print the profits array correctly between template tags but I can't inside the setup() function.
I just receive an object and I can't access to the array nested into it. Basically I need to set profits array inside new_series to plot cumulative profits in apexchart.
This is my DOM printing profits.value from the component:
enter image description here
In your console.log('ARRAY', profits), you don't access profits.value, whereas you do do that everywhere else. The template understands how to access the value automatically when you return just profits from your setup function.
const profitsValue = profits.value;
console.log('ARRAY', profitsValue);
You can then use that value in your series and keep your current return statement from setup()
Need help passing data "locationpos"= index of my Locations[] from function to class. I'm very new to React and I'm not sure what I'm doing wrong.
ERROR
Failed to compile
./src/components/data.js
Line 20:30: 'locationpos' is not defined no-undef
Search for the keywords to learn more about each error.
This error occurred during the build time and cannot be dismissed.
class Data {
constructor(locationpos) {
this.locationpos=locationpos;
this.updateData();
}
getTimes(date = null) {
date = date === null ? moment().format('DD/MM/YYYY') : date;
var data = this.getData();
return data ? data[date] : [];
}
getSpeadsheetUrl() {
return config.myData[locationpos];
}
function Daily({ locationProps = 1, root }) {
const context = useContext(ThemeContext);
const localization = useCallback(() => {
if (root && cookies.get("location") !== undefined) {
return cookies.get("location");
}
return locationProps;
}, [locationProps, root]);
const [locationState] = useState(localization());
const handleClick = event => {
window.focus();
notification.close(event.target.tag);
};
const openNav = () => {
document.getElementById("sidenav").style.width = "100%";
};
const closeNav = e => {
e.preventDefault();
document.getElementById("sidenav").style.width = "0";
};
// eslint-disable-next-line
const locationpos = locations.indexOf(locations[locationState]);
const _data = useRef(new Data(locationpos));
const getTimes = () => _data.current.getTimes();
Inside your data class, you need to use the instance variable as this.locationPos
getSpeadsheetUrl() {
return config.myData[this.locationpos];
}
I started integrating websockets into an existing React/Django app following along with this example (accompanying repo here). In that repo, the websocket interface is in websockets.js, and is implemented in containers/Chat.js.
I can get that code working correctly as-is.
I then started re-writing my implementation to use Hooks, and hit a little wall. The data flows through the socket correctly, arrives in the handler of each client correctly, and within the handler can read the correct state. Within that handler, I'm calling my useState function to update state with the incoming data.
Originally I had a problem of my single useState function within addMessage() inconsistently firing (1 in 10 times?). I split my one useState hook into two (one for current message, one for all messages). Now in addMessage() upon receiving data from the server, my setAllMessages hook will only update the client where I type the message in - no other clients. All clients receive/can log the data correctly, they just don't run the setAllMessages function.
If I push to an empty array outside the function, it works as expected. So it seems like a problem in the function update cycle, but I haven't been able to track it down.
Here's my version of websocket.js:
class WebSocketService {
static instance = null;
static getInstance() {
if (!WebSocketService.instance) {
WebSocketService.instance = new WebSocketService();
}
return WebSocketService.instance;
}
constructor() {
this.socketRef = null;
this.callbacks = {};
}
disconnect() {
this.socketRef.close();
}
connect(chatUrl) {
const path = `${URLS.SOCKET.BASE}${URLS.SOCKET.TEST}`;
this.socketRef = new WebSocket(path);
this.socketRef.onopen = () => {
console.log('WebSocket open');
};
this.socketRef.onmessage = e => {
this.socketNewMessage(e.data);
};
this.socketRef.onerror = e => {
console.log(e.message);
};
this.socketRef.onclose = () => {
this.connect();
};
}
socketNewMessage(data) {
const parsedData = JSON.parse(data);
const { command } = parsedData;
if (Object.keys(this.callbacks).length === 0) {
return;
}
Object.keys(SOCKET_COMMANDS).forEach(clientCommand => {
if (command === SOCKET_COMMANDS[clientCommand]) {
this.callbacks[command](parsedData.presentation);
}
});
}
backend_receive_data_then_post_new(message) {
this.sendMessage({
command_for_backend: 'backend_receive_data_then_post_new',
message: message.content,
from: message.from,
});
}
sendMessage(data) {
try {
this.socketRef.send(JSON.stringify({ ...data }));
} catch (err) {
console.log(err.message);
}
}
addCallbacks(allCallbacks) {
Object.keys(SOCKET_COMMANDS).forEach(command => {
this.callbacks[SOCKET_COMMANDS[command]] = allCallbacks;
});
}
state() {
return this.socketRef.readyState;
}
}
const WebSocketInstance = WebSocketService.getInstance();
export default WebSocketInstance;
And here's my version of Chat.js
export function Chat() {
const [allMessages, setAllMessages] = useState([]);
const [currMessage, setCurrMessage] = useState('');
function waitForSocketConnection(callback) {
setTimeout(() => {
if (WebSocketInstance.state() === 1) {
callback();
} else {
waitForSocketConnection(callback);
}
}, 100);
}
waitForSocketConnection(() => {
const allCallbacks = [addMessage];
allCallbacks.forEach(callback => {
WebSocketInstance.addCallbacks(callback);
});
});
/*
* This is the problem area
* `incoming` shows the correct data, and I have access to all state
* But `setAllMessages` only updates on the client I type the message into
*/
const addMessage = (incoming) => {
setAllMessages([incoming]);
};
// update with value from input
const messageChangeHandler = e => {
setCurrMessage(e.target.value);
};
// Send data to socket interface, then to server
const sendMessageHandler = e => {
e.preventDefault();
const messageObject = {
from: 'user',
content: currMessage,
};
setCurrMessage('');
WebSocketInstance.backend_receive_data_then_post_new(messageObject);
};
return (
<div>
// rendering stuff here
</div>
);
}
There is no need to rewrite everything into functional components with hooks.
You should decompose it functionally - main (parent, class/FC) for initialization and providing [data and] methods (as props) to 2 functional childrens/components responsible for rendering list and input (new message).
If you still need it ... useEffect is a key ... as all code is run on every render in functional components ... including function definitions, redefinitions, new refs, duplications in callbacks array etc.
You can try to move all once defined functions into useEffect
useEffect(() => {
const waitForSocketConnection = (callback) => {
...
}
const addMessage = (incoming) => {
setAllMessages([incoming]);
};
waitForSocketConnection(() => {
...
}
}, [] ); // <<< RUN ONCE