React Thunk Resolver reasie error: A computed property name must be of type 'string', 'number', 'symbol', or 'any' - redux-thunk

Got this error:
A computed property name must be of type 'string', 'number', 'symbol', or 'any'.
In this line
> [getAuthnUser.fulfilled](state, { payload }) {
Component:
import { createSlice, createAsyncThunk, PayloadAction } from '#reduxjs/toolkit'
import { AuthnRes } from '../tikexModule/Types'
import axios from 'axios'
const initialState: any = {
resp: null,
}
const namespace = 'user'
export const getAuthnUser = createAsyncThunk(
`${namespace}/getAuthnUser`,
async () => {
const { data } = await axios({
method: 'get',
url: 'me',
headers: { crossDomain: true },
})
return data
}
)
const userSlice = createSlice({
name: 'authnUser',
initialState,
reducers: {},
extraReducers: {
[getAuthnUser.fulfilled](state, { payload }) {
state.resp = payload
},
},
})
export default userSlice.reducer

We do not recommend the object notation for extraReducers any more, especially with TypeScript you should be using the "builder notation".
As you see, the object notation is not playing well with TypeScript.
extraReducers: builder => {
builder.addCase(getAuthnUser.fulfilled, (state, { payload }) {
state.resp = payload
}),
},

Related

How to write test Jest + extraReducers (RTK Query)?

I tried to test extra reducers in this way. Here is an example of a reducer with extra reducers and a small test that does not work for me because the state does not change.
import { createSlice } from "#reduxjs/toolkit";
export const initialState: SchemeState = {
schemePlace: undefined,
};
const schemeSlice = createSlice({
name: "scheme",
initialState,
extraReducers: (builder) => {
builder.addMatcher(schemeApi.endpoints.getSchemePlace.matchFulfilled, (state, action) => {
state.schemePlace = action.payload;
});
},
});
TEST
it("handle extraReducers", () => {
const action = {
type: schemeApi.endpoints.getSchemePlace.matchFulfilled,
payload: {
id: 1,
name: "str",
},
};
expect(reducer(undefined, action)).toEqual({
schemePlace: {
id: 1,
name: "str",
}
});
});
My example doesn't work, state doesn't change. I don't know which type do I need for action?

How can I build nodes and use them to create pages in gatsby?

I'm able to run my code in dev just fine and works as expected. Not sure what I'm doing wrong. Am I unable to create nodes and then build pages from them in gatsby-node.js? Is there a better way of doing this in gatsby that I'm not aware of?
The problem is when I try to build I receive error.
"gatsby-node.js" threw an error while running the sourceNodes lifecycle:
Request failed with status code 400
Here is my code:
exports.sourceNodes = async ({
actions,
createNodeId,
createContentDigest,
}) => {
const { createNode } = actions
const auth_token = Buffer.from(
`${client_id}:${client_secret}`,
'utf-8'
).toString('base64')
const token_url = 'https://accounts.spotify.com/api/token'
const data = qs.stringify({ grant_type: 'client_credentials' })
const response = await axios.post(token_url, data, {
headers: {
Authorization: `Basic ${auth_token}`,
'Content-Type': 'application/x-www-form-urlencoded',
},
})
const access_token = await response.data.access_token
const spotifyData = await axios.get(
`https://api.spotify.com/v1/artists/${artistId}/albums`,
{
headers: {
Authorization: `Bearer ${access_token}`,
'Content-type': 'application/json',
},
params: {
limit: 50,
market: 'US',
groups: 'single,album',
},
}
)
const ALBUM_NODE_TYPE = `Album`
await spotifyData.data.items.forEach(album =>
createNode({
...album,
id: createNodeId(`${ALBUM_NODE_TYPE}-${album.id}`),
parent: null,
children: [],
internal: {
type: ALBUM_NODE_TYPE,
contentDigest: createContentDigest(album),
},
})
)
}
exports.createPages = async ({ graphql, actions }) => {
const { createPage } = actions
const results = await graphql(`
{
collections: allFile {
distinct(field: sourceInstanceName)
edges {
node {
id
sourceInstanceName
childMarkdownRemark {
id
fields {
slug
}
frontmatter {
title
image
}
}
}
}
}
news: allFile(filter: { sourceInstanceName: { eq: "news" } }) {
nodes {
sourceInstanceName
childMarkdownRemark {
frontmatter {
title
image
blurb
url
}
id
fields {
slug
}
}
}
}
music: allAlbum(sort: { fields: release_date, order: DESC }) {
nodes {
id
href
images {
url
}
name
artists {
name
}
release_date
album_type
external_urls {
spotify
}
}
}
}
`)
// Music
await results.data.music.nodes.forEach(node => {
console.log(node)
if (node.errors) {
node.errors.forEach(e => console.error(e.toString()))
return Promise.reject(node.errors)
}
const id = node.id
const name = node.name.replace(/\s+/g, '_').toLowerCase()
createPage({
path: `music/${name}`,
component: path.resolve(`src/templates/music/music.js`),
// additional data can be passed via context
context: {
id,
field: { ...node },
},
})
})
await results.data.news.nodes.forEach(node => {
if (node.errors) {
node.errors.forEach(e => console.error(e.toString()))
return Promise.reject(node.errors)
}
const id = node.childMarkdownRemark.id
createPage({
path: `${node.sourceInstanceName}${node.childMarkdownRemark.fields.slug}`,
component: path.resolve(
`src/templates/${String(node.sourceInstanceName)}/${String(
node.sourceInstanceName
)}.js`
),
// additional data can be passed via context
context: {
id,
field: { ...node.childMarkdownRemark.frontmatter },
},
})
})
//News Collection
await results.data.collections.distinct.forEach(collection => {
if (collection.errors) {
collection.errors.forEach(e => console.error(e.toString()))
return Promise.reject(collection.errors)
} else {
if (collection !== 'news') {
return
} else {
const edges = results.data.collections.edges
const nodes = edges.filter(
e => e.node.sourceInstanceName === 'news'
)
createPage({
path: `/collections/news`,
component: path.resolve(
`src/templates/news/collections/news.js`
),
context: {
nodes: { ...nodes },
},
})
}
}
})
}
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions
if (node.internal.type === `MarkdownRemark`) {
const value = createFilePath({ node, getNode })
createNodeField({
name: `slug`,
node,
value,
})
}
}
I also tried wrapping the createPage function in sourceNodes but that didn't work either.
I ended up creating a source-plugin and passing in my Spotify credentials as a string in gatbsy-config.js. It's not able to read env variable at build time but it is when running dev and I'm not sure I understand why that is.

Dispatch RTK Query mutation inside redux-observable epic

I'm using redux toolkit to create slices:
import { createSlice } from '#reduxjs/toolkit';
const thingSlice = createSlice({
...
reducers: {
setThing(state, action) {}
}
});
export const { setThing } = thingSlice.actions;
I'm using RTK Query to build mutations:
import { createApi, fetchBaseQuery } from '#reduxjs/toolkit/query/react';
const api = createApi({
reducerPath: 'api',
baseQuery: fetchBaseQuery({ baseUrl: '' }),
endpoints: (build) => ({
postThing: build.mutation({
query: () => ({ url: `/api/thing`, method: 'POST', body: 'thing' }),
})
})
}}
I'm using redux-observable epics for complex actions logic.
How do I return a mutation action inside an epic?
import { setThing } from './thingSlice';
const somethingEpic = (actions$, state$) =>
actions$.pipe(
filter(setThing.match),
mergeMap(() => {
// how to dispatch "postSomething" here?
})
);

How to access the value of a constant outside a function?

I am using Node with websocket and I have this function:
const validatedCep = async () => {
const data = await axios
.get(`https://viacep.com.br/ws/${message}/json/`)
.then((res) => {
return res.data;
})
.catch((err) => {
return err.response;
});
console.log(1, data);
return data;
};
if (this.props.dataType === "CEP") {
validatedCep();
}
How can I get the value returned in response and access that value outside the validatedCep function?
I need this value to be able to check if it will return the value of the answer or an error, so that I can proceed with the logic of the function.
Full function:
import { MessageSender } from "./message-sender";
import { WappMessage } from "./wapp-message";
import axios from "axios";
export type FormProps = {
error?: string;
text: string;
dataType: string;
typingDuration: number;
};
export class WappFormMessage extends WappMessage<FormProps> {
constructor(
readonly props: FormProps,
private next: WappMessage<any> | undefined,
protected messageSender: MessageSender<FormProps>
) {
super(props, "response", true, messageSender);
}
getNext(message: string): WappMessage<any> | undefined {
const regexs = [
{ type: "email", regex: "^[a-z0-9]+#[a-z0-9]+\\.[a-z]+\\.?([a-z]+)?$" },
{ type: "CPF", regex: "^\\d{3}\\.?\\d{3}\\.?\\d{3}\\-?\\d{2}$" },
{ type: "CNPJ", regex: "^d{2}.?d{3}.?d{3}/?d{4}-?d{2}$" },
{
type: "cellPhone",
regex: "(^\\(?\\d{2}\\)?\\s?)(\\d{4,5}\\-?\\d{4}$)",
},
{ type: "phone", regex: "(^\\(?\\d{2}\\)?\\s?)(\\d{4}\\-?\\d{4}$)" },
{ type: "birthDate", regex: "(^\\d{2})\\/(\\d{2})\\/(\\d{4}$)" },
];
const dataTypes = [
"email",
"birthDate",
"CPF",
"CNPJ",
"cellPhone",
"phone",
];
const validateData = (element: string) => {
if (this.props.dataType === element) {
const getRegex = regexs.find((regexs) => regexs.type === element);
const regexCreate = new RegExp(getRegex!.regex, "i");
const validate = regexCreate.test(message);
return validate;
}
return true;
};
const isValid = dataTypes.find(validateData);
if (!isValid) {
return new WappFormMessage(
{
error: "Invalid data!",
...this.props,
},
this.next,
this.messageSender
);
}
const validatedCep = async () => {
const data = await axios
.get(`https://viacep.com.br/ws/${message}/json/`)
.then((res) => {
return res.data;
})
.catch((err) => {
return err.response;
});
console.log(1, data);
return data;
};
if (this.props.dataType === "CEP") {
validatedCep();
}
return this.next;
}
async send(remoteJid: string): Promise<void> {
await this.messageSender.send(
remoteJid,
this.props,
this.props.typingDuration
);
}
}

Apollo GraphQL v3 subscription returning null

I'm having a super hard time with setting up subscriptions in apollo-server. It's listening, I can make the mutation and query the result. But, the subscription for the same data returns null every time. Here are the important parts of my code:
import { Storage } from "#google-cloud/storage"
import { createError } from "apollo-errors"
import { ApolloServer, gql, PubSubEngine } from "apollo-server-express"
import { PubSub } from "apollo-server"
import cors from "cors"
import express from "express"
import jwt from "express-jwt"
import jwksRsa from "jwks-rsa"
import neo4j from "neo4j-driver"
import { initializeDatabase } from "./initialize"
import { typeDefs } from "./schema.js"
import { createServer } from "HTTP"
const pubsub = new PubSub()
const app = express()
const messages = []
const resolvers = {
Mutation: {
postMessage(parent, { user, content }, context) {
const id = messages.length
messages.push({
id,
user,
content,
})
pubsub.publish("test", {
messages,
})
return id
},
},
Query: {
messages: () => messages,
},
Subscription: {
messages: {
subscribe: (parent, args, context) => {
return pubsub.asyncIterator("test")
},
},
},
}
const neoSchema = new Neo4jGraphQL({
typeDefs,
resolvers,
config: {
jwt: {
secret: process.env.NEO4J_GRAPHQL_JWT_SECRET,
},
},
debug: true,
})
const NEO4J_USER = process.env.NEO4J_USER
const NEO4J_PASS = process.env.NEO4J_PASS
const NEO4J_URI = process.env.NEO4J_URI
const driver = neo4j.driver(NEO4J_URI, neo4j.auth.basic(NEO4J_USER, NEO4J_PASS))
const init = async (driver) => {
await initializeDatabase(driver)
}
try {
init(driver).catch((e) => console.log(e))
console.log("ne4j initialized...")
} catch (error) {
console.error(`Failed to property initialize database`, error)
}
const apolloServer = new ApolloServer({
schema: neoSchema.schema,
context: ({ req }) => {
return {
driver,
pubsub,
req,
}
},
subscriptions: {
onConnect: async (connectionParams, webSocket, context) => {
console.log("xxx")
console.log(connectionParams)
},
onDisconnect: (websocket, context) => {
console.log("WS Disconnected!")
},
path: "/graph",
},
introspection: true,
playground: true,
})
apolloServer.applyMiddleware({ app, path: "/graph" })
const httpServer = createServer(app)
apolloServer.installSubscriptionHandlers(httpServer)
const port = process.env.PORT || 8080
httpServer.listen({ port }, () => {
console.log(`Server is ready at http://localhost:${port}${apolloServer.graphqlPath}`)
console.log(`Subscriptions ready at ws://localhost:${port}${apolloServer.subscriptionsPath}`)
})
And from my schema:
export const typeDefs = gql`
type Message {
id: ID!
user: String!
content: String!
}
type Query {
messages: [Message!]
}
type Subscription {
messages: [Message!]
}
type Mutation {
postMessage(user: String!, content: String!): ID!
}
`
If I execute a mutation on postMessage, then query messages, I get the expected data back. However, when I run the subscription from the client, I get
{
"data": {
"messages": null
}
}
What's happening here? What am I missing? Is there something missing in my server setup? Are my pubsub and subscriptions code off?

Resources