nested websocket function always returning undefined - javascript

I'm using websockets from this library: https://www.npmjs.com/package/websocket
This is a function in React.ts 17 that successfully retrieves the data from the server, but fails to return the values of the function itself.
const recieveMessages = () => {
client.onmessage = (message: any) => {
const dataFromServer = JSON.parse(message.data)
console.log(dataFromServer) //This successfully logs the data
return dataFromServer //This is always returned as undefined
}
//I've tried a few versions with the return statement here without any success.
}
How can I make the recieveMessages function return the data from the client.onmessage function?
Update: I'm trying to seperate all the logic into a seperate React hook(useWebSocket) which currently looks like this:
import { w3cwebsocket } from 'websocket'
export const useWebSocket = () => {
const client = new w3cwebsocket('ws://127.0.0.1:8000')
const connectToServer = () => {
client.onopen = () => { console.log('Websocket client connected') }
}
const recieveMessages = () => {
client.onmessage = (message: any) => {
const dataFromServer = JSON.parse(message.data)
console.log('reply from server: ', dataFromServer)
return dataFromServer
}
}
const sendMessage = (message: any) => {
client.send(JSON.stringify('lol'))
}
const onCloseServer = (event: CloseEvent) => {
console.log(event)
}
return {
connectToServer,
recieveMessages,
sendMessage,
onCloseServer
}
}
I'm then trying to run the function inside the useEffect in a separate component like this:
The desire is to set the following data inside the local state of this component.
useEffect(() => {
recieveMessages()
setState(recieveMessages()) //This is always undefined
}, [])

This calls for a useState hook inside your useWebSocket hook.
Whenever client.onmessage receives a message, store that message inside of a state and update it every time another message is received.
Then return the state from the hook.
import { useState } from 'react'
import { w3cwebsocket } from 'websocket'
export const useWebSocket = () => {
const [receivedMessage, setReceivedMessage] = useState('')
const client = new w3cwebsocket('ws://127.0.0.1:8000')
client.onmessage = (message: any) => {
const dataFromServer = JSON.parse(message.data)
setReceivedMessage(dataFromServer)
}
const sendMessage = (message: any) => {
client.send(JSON.stringify(message))
}
return {
receivedMessage,
sendMessage,
}
}
Then implement it like so. The receivedMessage value is the state that will be updated and can be monitered with a useEffect hook to do something whenever a message has been received.
const { receivedMessage, sendMessage } = useWebSocket()
useEffect(() => {
if (receivedMessage !== '') {
// Do something whenever the received message is changed.
sendMessage('Received you loud and clear')
}
}, [receivedMessage])

Related

Functions is executed before the data is taken from state in React Javascript

So when the visitors visits for the first time, if they don't have those information I require on the localStorage, it should set them then fetch the data. But the problem is it shows as null when I fetches the data. I tried async but I don't know.
So basically I want all of the localStorage and state to be set before the getData functions is runned.
useEffect(() => {
(async function () {
try {
if (localStorage.getItem('language') === null) {
localStorage.setItem('language', 'en');
setLanguage('en')
}
if (localStorage.getItem('view') === null) {
localStorage.setItem('view', 'verses');
setView('verses');
}
getData(`${view}_${language}`);
} catch (e) {
console.error(e);
}
})();
}, []);
Here is the function it calls:
const getData = async (where) => {
try {
const { data: content, error } = await supabase
.from(where)
.select('*')
if (error) throw error;
if (content) {
const randomizer = content[Math.floor(Math.random() * content.length)];
setContent(randomizer);
}
} catch (error) {
alert(error.error_description || error.message)
} finally {
// console.log(content.content)
}
}
and here are the states:
const [view, setView] = useState(null);
const [language, setLanguage] = useState(null);
const [content, setContent] = useState(null);
Doesn't matter if you keep them inside the async, the state update itself is async, perhaps you can do the following:
const [language, setLanguage] = useState(localStorage.getItem('language') || 'en');
useEffect(() => {
localStorage.setItem('language', language);
}, [language])
// and same for view
useEffect(() => {
if(language && view) {
getData(`${view}_${language}`);
}
}, [language, view])
I assume these states, language and view, are changed somehow in your app, otherwise you most likely don't need to keep them in state.

How to create reusable function that uses state and props in React

I have a function that sends data to the server and uses props and set.... It is the same throughout few components. It gets called when a certain event occurs.
How can I refactor it out of those components into a single place?
I was thinking about using hooks but because it gets triggered by an event I don't think using a hook is a good approach.
async function sendDataToServer(data) {
const url = new URL(buildUrl());
let timeout = setTimeout(() => setPostingState(SendingState.Sending), 250);
try {
const response = props.id
? await axios.put(url, data)
: await axios.post(url, data);
setPostingState(SendingState.Idle);
props.onSaved(props.id ? props.id : response.data, data);
}
catch (error) {
setPostingState(SendingState.Error);
}
clearTimeout(timeout);
}
function handleSubmit(e) { ... sendDataToServer(data); ... }
You can make a curried function:
// helpers.js
export const genSendDataToServerCallback = ({ setState, onSaved, id }) => async (
data
) => {
const url = new URL(buildUrl());
let timeout = setTimeout(() => setState(SendingState.Sending), 250);
try {
const response = await (props.id
? axios.put(url, data)
: axios.post(url, data));
setState(SendingState.Idle);
onSaved(id ? id : response.data, data);
} catch (error) {
setState(SendingState.Error);
}
clearTimeout(timeout);
};
// Usage in some component
import { genSendDataToServerCallback } from './helpers.js'
const sendDataToServer = genSendDataToServerCallback({setter:setPostingState, ...props});
function handleSubmit(e) { sendDataToServer(data); }
// Usage in other component with different setter
const sendDataToServer = genSendDataToServerCallback({setter:setState, ...props});
function handleSubmit(e) { sendDataToServer(data); }

how to solve console log issue in chrome browser

I'm getting data from an API and initially when console it in fetchData function it works but when console it in fetchDailyData function and call this function in another component it didn't work.
How can I solve this issue?
import axios from 'axios';
const url = `https://covid19.mathdro.id/api`;
export const fetchData = async () => {
try {
const { data: { confirmed, recovered, deaths, lastUpdate }} = await axios.get(url);
return { confirmed, recovered, deaths, lastUpdate };
} catch (error) {
}
}
export const fetchDailyData = async () => {
try {
const { data } = await axios.get(`${url}/daily`);
console.log(data); // <<==>> chrome browser is not showing this console log
// fetchDailyData function called in another component
} catch (error) {
}
}
Calling fetchDailyData function in another component
when I call console.log, I can't see the data in console of my browser
const Chart = () => {
const [dailyData, setDailyData] = useState({});
useEffect(() => {
const fetchApi = async () => {
setDailyData(await fetchDailyData());
}
console.log(dailyData);
fetchApi();
});
};
https://covid19.mathdro.id/api/daily which is your url in fetchDailyData doesn't return any data currently at all.
I suppose you have to check if this backend still available. And it is a good practice to check the response status (normally it should return statusCode 200) in response callback.

useMutation always returns data undefined

this my code
React
const EXCHANGE_RATES = gql`
mutation {
signUp(lastName: "Amasia")
}
`;
const HandlerRequest = () => {
const [loading, { data }] = useMutation(EXCHANGE_RATES);
console.log('apollo', data);
return <p>apollo</p>;
};
Schema
gql`
extend type Mutation {
signUp(
lastName: String!
): String!
}
`;
Resolvers
Mutation: {
signUp: async (
_,
{ lastName}
) => {
try {
console.log(lastName)
return lastName;
} catch (error) {
return 'error';
}
},
},
useMutation always returns data undefined but at graphql playground are working.what am i doing netak ?.
useMutation should return a function to call to execute the mutation. Generally you would hook this up to a button or something. It seems a little odd to use a mutation that executes automatically when the component loads.
const HandlerRequest = () => {
const [getExchangeRates, { data }] = useMutation(EXCHANGE_RATES);
// Load data if not already loaded.
if (!data) { getExchangeRates(); }
console.log('apollo', data);
return <p>apollo</p>;
};
Using the above you'll likely see two console.logs.
The initial component render, should be undefined
When getExchangeRates returns and data updates the component will be rerendered and the log will be called again.
Use the onCompleted callback and remember to pass the data object:
const [loading, { data }] = useMutation(EXCHANGE_RATES, {
onCompleted: (data) => {
console.log(data);
}
});
Your usage of useMutation is not quite correct. Here is the correct usage.
You also need to execute the mutation. data will be undefined until then.
const SomeComponent = () => {
const [doExchangeRates, { data, loading, error }] = useMutation(
EXCHANGE_RATES,
onCompleted: (data) => { console.log({data}); }
);
return <p onClick={doExchangeRates} >apollo</p>;
};
You can see full docs on useMutation here.

Getting an Async action creator test to pass Redux

I have an async actionCreator which sends off an API call - on success it gives the reponse on failure - it fails. I am writing tests for the call but I can't get the test to send back the correct response.
Here is the function I am testing - Each dispatch dispatches an action.
const getStudyData = () => {
return async dispatch => {
try {
dispatch(fetchStudiesBegin());
const res = await DataService.fetchAllStudyData();
dispatch(fetchStudiesSuccess(res))
}
catch (err) {
dispatch(fetchStudiesError(err))
}
}
}
const fetchStudiesBegin = () => ({
type: types.FETCH_STUDIES_BEGIN
});
const fetchStudiesSuccess = studies => ({
type: types.FETCH_STUDIES_SUCCESS,
payload: { studies }
});
const fetchStudiesError = error => ({
type: types.FETCH_STUDIES_ERROR,
payload: { error }
});
This is the test that I have written - It is however giving me the ERROR response instead of the SUCCESS response
import configureStore from 'redux-mock-store';
const middlewares = [ thunk ];
const mockStore = configureStore(middlewares);
import fetchMock from 'fetch-mock';
describe('Test thunk action creator for the API call for studies ', () => {
it('expected actions should be dispatched on successful request', () => {
const store = mockStore({});
const expectedActions = [
types.FETCH_STUDIES_BEGIN,
types.FETCH_STUDIES_SUCCESS
];
// Mock the fetch() global to always return the same value for GET
// requests to all URLs.
fetchMock.get('*', { response: 200 });
return store.dispatch(dashboardOperations.getStudyData())
.then(() => {
const actualActions = store.getActions().map(action => action.type);
expect(actualActions).toEqual(expectedActions);
});
fetchMock.restore();
});
});
});

Categories