RTK Query get object inside result - redux-toolkit

my getMovies returns object data but what i need is data.result inside data. How can I directly get data.result?
My API: https://movie-flask.c3-na.altogic.com/movies
My code:
export const movieApi = createApi({
reducerPath: 'movieApi',
baseQuery: fetchBaseQuery({
baseUrl: 'https://movie-flask.c3-na.altogic.com/'
}),
tagTypes: [],
endpoints: (builder) => ({
getMovies: builder.query({
query: () => "movies",
})
}),
})
// Export hooks for usage in functional components
export const { useGetMoviesQuery } = movieApi
I have tried
getMovies: builder.query({
query: () => "movies",
}).result
It does not work.
Below is how i call useGetMoviesQuery
const { data, error, isLoading } = useGetMoviesQuery();
{data && data.result && data.result.map((item, i) => (
<Text key={i}>
{item.name}
</Text>
))}
I want to get rid of data.result and directly want to call it with data.map.
Thanks.

You can use transformResponse:
getMovies: builder.query({
query: () => 'movies',
transformResponse: response => {
return response.result
},
})

Related

Can I dispatch another rtk query from queryFn and await it before continuing?

Essentially I want to await a bunch of queries before resolving a queryFn. An example of this is as follows:
What I know I can do currently
I'm aware I can do the following however this looks like it could get messy for more complex examples.
queryFn: async (
{ emailAddress, password },
{ dispatch },
_,
baseQuery,
) => {
await cognito.login(emailAddress, password)
const { data, error } = await baseQuery({
url: `me`,
method: 'GET',
})
await dispatch(
userService.util.updateQueryData('getUser', {}, (draft) => {
draft = data
}),
)
return { data, error }
},
What I'd like to do
Doing the following would mean I don't have to updateQueryData and duplicate endpoint URLs. Also it would mean that I can use errors from other queries to determine if the whole process went as planned.
queryFn: async (
{ emailAddress, password },
{ dispatch },
) => {
await cognito.login(emailAddress, password)
const {data,error} = dispatch(userService.endpoints.getUser.initiate({ }, { forceRefetch })) // await this
It looks like this was more simple than I'd thought
login: builder.mutation<{}, Req['login']>({
queryFn: async ({ emailAddress, password }, { dispatch }) => {
await Promise.resolve() // do stuff like hit cognito, an api ect
return dispatch(
userService.endpoints.getUser.initiate({}, { forceRefetch: true }),
)
},
}),
getUser: builder.query<Res['user'], Req['getUser']>({
queryFn: async (args, _, _2, baseQuery) => {
throw 'Hi i am an error'
},
}),
// this becomes {message:"Hi I am an error"} proving it's awaited
const [login, { error, data }] = useLoginMutation({})

Pass callback to transformResponse in RTK Query endpoint

I have a RTK query API
export const api = createApi({
baseQuery: graphqlRequestBaseQuery({
// ...
}),
endpoints: (builder) => ({
getPeople: builder.query({
query: (params) => ({
document: params,
}),
transformResponse: (response) => {
// I wanna call a function here that I'm passing to this endpoint
},
}),
}),
});
and in my UI
const { data: people, isLoading: isLoadingPeople } = useGetPeopleQuery(people);
I'm wondering how can I pass a callback function from the UIs hook to the endpoint so that I can call it from transformResponse.

Nexjs + SWR: API resolved without sending a response for /api/projects/<slug>, this may result in stalled requests

Since on first render I was not able to get the router.query I am passing the params from getServerSideProps as follows:
export async function getServerSideProps(context) {
return {
props: { params: context.params },
};
}
Then in the function am trying to do the API call but am getting the API stalled error
API resolved without sending a response for
/api/projects/nichole_robel23, this may result in stalled requests.
This is my code:
export default function Project({ params }) {
const { slug } = params;
let [projectData, setProjectData] = useState([]);
let [loading, setLoading] = useState(true);
const { data } = useSWR('http://localhost:3000/api/projects/' + slug);
useEffect(() => {
if (data) {
setProjectData(data.data.project);
setLoading(false);
}
}, [data]);
......
I have global SWRCofig as follows
<SWRConfig value={{ fetcher: (url) => axios(url).then(r => r.data) }}>
<Layout>
<Component {...pageProps} />
</Layout>
</SWRConfig>
Any way to solve the problem?
You are missing your fetcher–the function that accepts the key of SWR and returns the data, so the API is not being called.
You are also not returning a response correctly from the API–this is most likely a case of not waiting for a promise/async to be fulfilled correctly.
CLIENT
const fetcher = (...args) => fetch(...args).then((res) => res.json());
export default function Home({ params }) {
const { slug } = params;
const [projectData, setProjectData] = useState([]);
const [loading, setLoading] = useState(true);
const { data } = useSWR(`http://localhost:3000/api/projects/${slug}`, fetcher);
useEffect(() => {
if (data) {
setProjectData(data);
setLoading(false);
}
}, [data]);
API
const getData = () => {
return new Promise((resolve, reject) => {
// simulate delay
setTimeout(() => {
return resolve([{ name: 'luke' }, { name: 'darth' }]);
}, 2000);
});
}
export default async (req, res) => {
// below will result in: API resolved without sending a response for /api/projects/vader, this may result in stalled requests
// getData()
// .then((data) => {
// res.status(200).json(data);
// });
// better
const data = await getData();
res.status(200).json(data);
}

Redux Toolkit state doesn't update even after adding extraReducers

I have a very limited understanding of the redux toolkit compared to its previous version. I am struggling to understand why isn't my state getting updated on the trigger of getUsers.
I have added the extraReducers as well.
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit';
import { fetchSample } from './filterAPI';
export const getUsers = createAsyncThunk(
'primaryFilters/getUsers',
async (dispatch, getState) => {
console.log(getState, dispatch);
const response = await fetchSample();
return response;
}
);
const primaryFiltersSlice = createSlice({
name: 'primaryFilters',
initialState: {
dateFilter: {
dates: {
key: 'selection',
startDate: new Date(),
endDate: new Date(),
},
dummyData: null,
},
status: null,
},
extraReducers: (builder) => {
builder
.addCase(getUsers.pending, (state) => {
state.status = 'loading';
})
.addCase(getUsers.fulfilled, (state, action) => {
state.status = 'idle';
state.dummyData = action.payload;
})
.addCase(getUsers.rejected, (state, action) => {
state.status = 'failed';
});
},
});
export default primaryFiltersSlice.reducer;
Here's fetchSample function:
export const fetchSample = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/todos/1');
return response.json();
};
Additionally, I want to point out that my status is triggering from pending to idle and so on but my actual state isn't updating.
Here's the screenshot for the same:
I would also like to know how can we log the messages within those extraReducers.
For one, looking at your data structure, you probably want to update state.dateFilter.dummyData, not state.dummyData - at least assuming you want to match your initialState structure.
Also, createAsyncThunk does not take a callback dispatch, getState:
correct would be
export const getUsers = createAsyncThunk(
'primaryFilters/getUsers',
async (arg, {dispatch, getState}) => {
(but that does not make a difference here since you are using neither)
As for logging... just console.log? Or do you mean you are getting a Proxz object? In that case console.log(current(state))
For some reason, I am able to dispatch actions by keeping the status update at the bottom instead of the top. I would love to have a better explanation for the same, here's what exactly fixed my code:
import { createAsyncThunk, createSlice } from '#reduxjs/toolkit';
import { fetchSample } from './filterAPI';
export const getUsers = createAsyncThunk(
'primaryFilters/getUsers',
async (dispatch, getState) => {
console.log(getState, dispatch);
const response = await fetchSample();
return response;
}
);
// export const updateDates = () => {
// }
const primaryFiltersSlice = createSlice({
name: 'primaryFilters',
initialState: {
dateFilter: {
dates: {
key: 'selection',
startDate: new Date(),
endDate: new Date(),
},
dummyData: null,
},
status: null,
},
reducer: {
updateDate: (state, action) => {
console.log('Actions = ', action);
},
},
extraReducers: (builder) => {
builder
.addCase(getUsers.pending, (state) => {
state.status = 'loading';
})
.addCase(getUsers.fulfilled, (state, action) => {
state.dummyData = action.payload;
state.status = 'idle';
})
.addCase(getUsers.rejected, (state, action) => {
state.status = 'failed';
});
},
});
export default primaryFiltersSlice.reducer;

Cannot read property 'find' of inherited method in unit tests

im having an issue trying to run an e2e test for my NestJS application tha uses a mongodb-memory-server to run mongo in memory
my e2e test looks like this
describe('UsersController.e2e', () => {
let app: INestApplication;
let module: TestingModule;
const mongod = new MongoMemoryServer();
beforeAll(async () => {
const port = await mongod.getPort();
const database = await mongod.getDbName();
module = await Test.createTestingModule({
providers: [UserRepository, UserService],
controllers: [UserController],
imports: [TypeOrmModule.forRootAsync({
useFactory: () => {
return {
type: 'mongodb',
host: '127.0.0.1',
port,
database,
entities: [__dirname + '../../../**/*.entity{.ts,.js}'],
} as TypeOrmModuleOptions;
},
}),
TypeOrmModule.forFeature([User])
]
}).compile();
app = module.createNestApplication();
await app.init();
});
afterAll(async () => {
await module.close();
await app.close();
});
describe('GET /users', () => {
it('should return a collection of user resources', async () => {
const { body } = await supertest
.agent(app.getHttpServer())
.get('/users')
.set('Accept', 'application/json')
.expect('Content-Type', /json/)
.expect(200);
expect(body).toEqual(userCollectionMock);
});
});
});
when running the test it throws a 500 error
Cannot read property 'find' of undefined
TypeError: Cannot read property 'find' of undefined
at UserRepository.Object.<anonymous>.MongoRepository.find (src/repository/MongoRepository.ts:77:29)
at UserRepository.index (src/modules/user/repositories/user.repository.ts:12:20)
the repository class looks like
export class UserRepository extends MongoRepository<User> implements IResourceRepository<User> {
index(): Promise<User[]> {
return this.find();
}
}
the extension of MongoRepository provides find() https://github.com/typeorm/typeorm/blob/master/src/repository/MongoRepository.ts#L76
So it perplexes me as to why it is undefined!
I know this is a month old, but I just ran into this issue and resolved it.
I'm using mongoose + typegoose with mongodb-memory-server.
import { MongoMemoryServer } from 'mongodb-memory-server';
describe('Auth', () => {
let app: INestApplication;
let mongoServer: MongoMemoryServer;
beforeAll(async () => {
// Set up database
mongoServer = new MongoMemoryServer();
const mongoUri = await mongoServer.getUri();
const moduleRef = await Test.createTestingModule({
imports: [
...
TypegooseModule.forRoot(mongoUri, {
useNewUrlParser: true,
useUnifiedTopology: true,
}),
...
],
controllers: [...],
providers: [...],
}).compile();
app = moduleRef.createNestApplication();
await app.init();
});
afterAll(async () => {
await mongoServer.stop();
});
});
The main mistake I was making was that I had separately overwritten my User Typegoose injection.
providers: [
// THIS WAS MY MISTAKE!
{
provide: getModelToken('User'),
useValue: mockUserModel,
},
],
I know this is not a complete answer to your question, but I hope this might help you.