How to implement an optimistic update when using reduxjs/toolkit - react-redux

My reducer file is below
const slice = createSlice({
name: "hotels",
initialState: {
list: [],
loading: false,
lastFetch: null,
},
reducers: {
hotelsRequested: (hotels) => {
hotels.loading = true;
},
hotelsRequestFailed: (hotels) => {
hotels.loading = false;
},
hotelsReceived: (hotels, action) => {
hotels.list = action.payload;
hotels.loading = false;
hotels.lastFetch = Date.now();
},
hotelEnabled: (hotels, action) => {
const { slug } = action.payload;
const index = hotels.list.findIndex((hotel) => hotel.slug === slug);
hotels.list[index].active = true;
},
},
});
export const {
hotelsReceived,
hotelsRequestFailed,
hotelsRequested,
hotelEnabled,
} = slice.actions;
export default slice.reducer;
//Action creators
export const loadHotels = () => (dispatch, getState) => {
const { lastFetch } = getState().entities.hotels;
const diffInMinutes = moment().diff(lastFetch, "minutes");
if (diffInMinutes < 10) return;
dispatch(
hotelApiCallBegan({
url: hotelUrl,
onStart: hotelsRequested.type,
onSuccess: hotelsReceived.type,
onError: hotelsRequestFailed.type,
})
);
};
export const enableHotel = (slug) =>
hotelApiCallBegan(
{
url: `${hotelUrl}${slug}/partial-update/`,
method: "put",
data: { active: true },
onSuccess: hotelEnabled.type,
},
console.log(slug)
);
My api request middleware function is as follows
export const hotelsApi = ({ dispatch }) => (next) => async (action) => {
if (action.type !== actions.hotelApiCallBegan.type) return next(action);
const {
onStart,
onSuccess,
onError,
url,
method,
data,
redirect,
} = action.payload;
if (onStart) dispatch({ type: onStart });
next(action);
try {
const response = await axiosInstance.request({
baseURL,
url,
method,
data,
redirect,
});
//General
dispatch(actions.hotelApiCallSuccess(response.data));
//Specific
if (onSuccess) dispatch({ type: onSuccess, payload: response.data });
} catch (error) {
//general error
dispatch(actions.hotelApiCallFailed(error.message));
console.log(error.message);
//Specific error
if (onError) dispatch({ type: onError, payload: error.message });
console.log(error.message);
}
};
Could anyone point me in the right direction of how to add an optimistic update reducer to this code. Currently on hitting enable button on the UI there's a lag of maybe second before the UI is updated. Or maybe the question, is do i create another middleware function to handle optimistic updates? If yes how do i go about that? Thanks

Related

Not getting Apollo Client subscription data

I'm trying to get subscription data. The server gives the data if you look through the Explorer.
Client:
const httpLink = createHttpLink({
uri
});
const wsLink =
typeof window !== "undefined"
? new GraphQLWsLink(
createClient({
url,
on: {
connected: () => console.log("Connected client!"),
closed: () => console.log("Closed ws-connection!"),
},
})
)
: null;
const splitLink =
typeof window !== "undefined" && wsLink != null
? split(
({ query }) => {
const def = getMainDefinition(query);
return (
def.kind === "OperationDefinition" &&
def.operation === "subscription"
);
},
wsLink,
httpLink
)
: httpLink;
const authLink = setContext((_, { headers }) => {
const {token} = useTokenFromCookie();
return {
headers: {
...headers,
authorization: token ? `Bearer ${token()}` : "",
}
}
});
const client = new ApolloClient({
link: authLink.concat(splitLink),
cache: new InMemoryCache({addTypename: false}),
defaultOptions: {
mutate: { errorPolicy: 'all' },
},
});
gql:
subscription ReadRegisterData($equipmentId: Int!, $addressRegistry: Int!) {
readRegisterData(equipment_id: $equipmentId, address_registry: $addressRegistry) {
equipment_id
address_registry
type_of
data_from_controller
}
}
Hook:
const useSubscriptionReadRegisterData = (equipment_ip:number, address_registry: number) => {
const { data, error, loading} = useSubscription(READ_REGISTER_DATA, {
variables: {
equipmentIp: equipment_ip,
addressRegistry: address_registry
}
});
console.log("data", data)
const dataRegisterSubscription = (data) ? data.readRegisterData : null;
return { dataRegisterSubscription, error, loading }
}
export default useSubscriptionReadRegisterData;
In the console writes:
The connection is established, then immediately the connection is closed
WS connection status 101
When you start listening to a subscription through Explorer, on the server, when outputting data to the log, you can see that there is 1 Listener. When you run in the application, it does not show any Listener

SocketIO 4 - won't emit to the room

I have following server code:
const path = require("path");
const http = require("http");
const express = require("express");
const {instrument} = require('#socket.io/admin-ui')
const {jwtDecode, jwtVerify, resignJwt} = require('jwt-js-decode')
const secret =
"xxxxxxx";
const app = express()
const server = http.createServer(app)
const io = require("socket.io")(server, {
cors: {
origin: ["https://admin.socket.io", "http://localhost:3001"],
credentials: true
},
});
let servantID = ''
io.use((socket, next) => {
const header = socket.handshake.headers["authorization"];
jwtVerify(header, secret).then((res) => {
if (res === true)
{
const jwt = jwtDecode(header);
servantID = jwt.payload.iss;
return next()
}
return next(new Error("authentication error"));
});
});
instrument(io, { auth: false });
server.listen(3000, () =>
console.log('connected')
)
io.on('connection', socket => {
socket.on("join", (room, cb) => {
console.log('Joined ' + room);
socket.join(room);
cb(`Joined the best room ${room}`)
});
socket.on('newOrder', function (data) {
socket.to('servant').emit('this', data);
console.log(data);
})
socket.on("thisNew", function (data) {
console.log('this new');
});
socket.on('disconnect', () => {
console.log('user disconnected');
});
})
And client side code:
socket.emit('join', 'servant', message => {
console.log(message)
})
socket.on('this', () => {
console.log('this event')
})
socket.emit('newOrder', 'data')
When I emit like this:
socket.to('servant').emit('this', data);
the client doesn't receive anything, but if I emit without room:
socket.emit('this', data);
the event and data are received on the client side.
What am I doing wrong here?

Apollo Websocket repeatedly attempts to connect over and over when updating context

I'm using Apollo on my frontend to manage queries and GQLgen on the backend to handle resolvers.
I've noticed this only occurs if webSocketInit returns a new ctx value. If I return the original ctx, everything works as expected.
//main.go
srv.AddTransport(&transport.Websocket{
Upgrader: websocket.Upgrader{
ReadBufferSize: 2048,
WriteBufferSize: 2048,
// Resolve cross-domain problems
CheckOrigin: func(r *http.Request) bool {
return true
},
},
InitFunc: func(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
return webSocketInit(ctx, initPayload)
},
KeepAlivePingInterval: 10 * time.Second,
})
func webSocketInit(ctx context.Context, initPayload transport.InitPayload) (context.Context, error) {
//Process auth token
ctxNew := context.WithValue(ctx, "token", token)
return ctxNew, nil
}
//client.tsx
useEffect(() => {
const unsubscribe = subscribeToMore({
document: MY_SUBSCRIPTION_GQL,
updateQuery: (prev, { subscriptionData }: any) => {
//...process new data
return Object.assign({}, prev, {
data: newData,
});
},
onError: (e) => {
console.log(e);
},
});
return () => unsubscribe();
}, []);
//apolloclient
const authLink = setContext((_, { headers }) => {
const token = store.getState().user.token;
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : '',
},
};
});
const wsLink =
typeof window !== 'undefined'
? new GraphQLWsLink(
createClient({
url: 'ws://localhost:8080',
lazy: true,
connectionParams: () => ({
Authorization: store.getState().user.token,
}),
on: {
connected: () => {
console.log('connected');
},
error: (e) => {
console.log(e);
},
},
})
)
: null;
// HTTP Requests
const httpLink = new HttpLink({
uri: `http://localhost:8080/`,
});
const link =
typeof window !== 'undefined' && wsLink != null
? split(
({ query }) => {
const def = getMainDefinition(query);
return def.kind === 'OperationDefinition' && def.operation === 'subscription';
},
wsLink,
authLink.concat(httpLink)
)
: authLink.concat(httpLink);
export const client = new ApolloClient({
link: link,
cache: new InMemoryCache({
addTypename: false,
}),
});

Network Request failed while sending image to server with react native

i want to send image to a server and getting the result with a json format but the application returns a Network Request failed error
react native 0.6 using genymotion as emulator
i tried RNFetchblob but the result take a long time to get response (5 min )
also i tried axios but it response with empty data with 200 ok
this is the function that import the image
OnClick = () => {
ImagePicker.showImagePicker(options, response => {
console.log("Response = ", response);
if (response.didCancel) {
console.log("User cancelled image picker");
} else if (response.error) {
console.log("Image Picker Error: ", response.error);
} else {
let source = { uri: response.uri };
// You can also display the image using data:
//let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
avatarSource: source,
data: response.data,
BtnDisabled: false
});
console.log();
}
});
};
and this method that sends the image
Send = async () => {
let url = "http://web001.XXX.com:8000/api/prediction/check_prediction/";
let UplodedFile = new FormData();
UplodedFile.append('file',{ type:'image/jpeg', uri : this.state.avatarSource , name:'file.jpeg'});
fetch(url, {
method: 'POST',
body:UplodedFile
})
.then(response => response.json())
.then(response => {
console.log("success");
console.log(response);
})
.catch(error => {
console.error(error);
});
i expect json format
ScreenShot here
can you change your code like this?
OnClick = () => {
ImagePicker.showImagePicker(options, response => {
console.log("Response = ", response);
if (response.didCancel) {
console.log("User cancelled image picker");
} else if (response.error) {
console.log("Image Picker Error: ", response.error);
} else {
let source = { uri: response.uri };
// You can also display the image using data:
//let source = { uri: 'data:image/jpeg;base64,' + response.data };
this.setState({
pickerResponse: response,
data: response.data,
BtnDisabled: false
});
console.log();
}
});
};
Send = async () => {
let url = "http://web001.XXX.com:8000/api/prediction/check_prediction/";
let UplodedFile = new FormData();
UplodedFile.append('file',{ type:'image/jpeg', uri : this.state.pickerResponse.path , name:'file.jpeg'});
axios({
method: "post",
url: url,
data: UplodedFile
})
.then(response => {
console.log("success");
console.log(response);
})
.catch(error => {
console.error(error);
});

Apollo Client delays request

I have a very weird issue with Apollo Client.
We are using apollo-client#1.9.3 with react (react-apollo#1.4.16).
In our project, we notice that apollo always wait for 1 to 2 seconds before sending the request.
Below is a screenshot of the situation:
This is how our client config looks like:
const customNetworkInterface = {
query: request =>
fetch('/graphql', {
method: 'POST',
credentials: 'include',
mode: 'cors',
cache: 'default',
headers: {
Accept: '*/*',
'Content-Type': 'application/json',
'X-Requested-With': 'XMLHttpRequest',
},
body: JSON.stringify({
...request,
query: print(request.query),
}),
})
.then(resp => resp.json())
.then(({ data, errors }) => {
if (errors) {
const userErrors = errors
.filter(({ code }) => +code >= 400 && +code <= 401)
.map(({ message }) => message)
.join('\n');
const serverErrors = errors
.filter(
({ code }) => !code || (+code < 400 && +code > 401)
)
.map(({ message }) => message)
.join('\n');
if (serverErrors.length > 0) {
error(serverErrors);
if (isProduction) {
window.triggerAlert(
'danger',
'The server encountered an error. Our technical team has been notified.'
);
} else {
window.triggerAlert('danger', serverErrors);
}
} else if (userErrors.length > 0) {
window.triggerAlert('danger', userErrors);
}
}
return { data, errors };
}),
};
const networkInterface = createNetworkInterface({
uri: '/graphql',
opts: {
credentials: 'same-origin',
},
});
networkInterface.useAfter([
{
applyAfterware({ response }, next) {
response
.clone()
.json()
.then(responseJson => {
if (responseJson.errors) {
error(
responseJson.errors
.map(({ message }) => message)
.join('\n')
);
}
next();
});
},
},
]);
export const client = new ApolloClient({
networkInterface: customNetworkInterface,
queryDeduplication: true,
addTypename: true,
});
Then the query code is with react-apollo:
graphql(RaceResultsQuery, {
props: ({ ownProps, data }) => ({
race_results: _.get(data, 'me.my_race_results', []),
}),
}),
This would need a complete, minimal example to provide an answer for sure (delete as much of your code as possible with the issue still happening).
My guess would be that you have a parent component with a very expensive query and it only renders the component with the delayed query after the expensive query returned.

Resources