This is my Graphql query for getting posts from headless wordpress:
export const GET_POSTS = gql`
query GET_POSTS( $uri: String, $perPage: Int, $offset: Int, $categoryId: Int ) {
posts: posts(where: { categoryId: $categoryId, offsetPagination: { size: $perPage, offset: $offset }}) {
edges {
node {
id
title
excerpt
slug
featuredImage {
node {
...ImageFragment
}
}
categories {
edges {
node {
categoryId
name
}
}
}
}
}
pageInfo {
offsetPagination {
total
}
}
}
}
${ImageFragment}
`;
When i do this: console.log("DATAAAA", data.posts.edges);
i get:
DATAAAA [
{
node: {
id: 'cG9zdDo0MA==',
title: 'postttt',
excerpt: '<p>dlkfjdsflkdslkdjfkldsf</p>\n',
slug: 'postttt',
featuredImage: null,
categories: [Object],
__typename: 'Post'
},
__typename: 'RootQueryToPostConnectionEdge'
},
{
node: {
id: 'cG9zdDox',
title: 'Hello world!',
excerpt: '<p>Welcome to WordPress. This is your first post. Edit or delete it, then start writing!</p>\n',
slug: 'hello-world',
featuredImage: null,
categories: [Object],
__typename: 'Post'
},
__typename: 'RootQueryToPostConnectionEdge'
}
]
But when try to go further, inside node, like this: console.log("DATAAAA", data.posts.edges.node); in order to get the categoryId which is inside categories: [Object], i get undefined.
How to get categoryId based on this query?
What i want to do is to get only the posts by a given category in getStaticProps like this, but i dont know how to get that categoryId dynamically. This is what my getStaticProps function looks like:
export async function getStaticProps(context) {
console.log("THE CONTEXT", context);
const { data, errors } = await client.query({
query: GET_POSTS,
variables: {
uri: context.params?.slug ?? "/",
perPage: PER_PAGE_FIRST,
offset: null,
categoryId: <===== How to get this dynamically?
},
});
const defaultProps = {
props: {
data: data || {},
},
revalidate: 1,
};
return handleRedirectsAndReturnData(defaultProps, data, errors, "posts");
}
This is my getStaticPaths function:
export async function getStaticPaths() {
const { data } = await client.query({
query: GET_CATEGORY_SLUGS_ID,
});
const pathsData = [];
data?.categories?.edges.node &&
data?.categories?.edges.node.map((category) => {
if (!isEmpty(category?.slug)) {
pathsData.push({ params: { slug: category?.slug } });
}
});
return {
paths: pathsData,
fallback: FALLBACK,
};
}
and this is what i get from context console.log("THE CONTEXT", context);:
THE CONTEXT {
params: { slug: 'uncategorized' },
locales: undefined,
locale: undefined,
defaultLocale: undefined
}
Any help would be appreciated.
Related
While creating the post (for the blog) using Jodit Editor, I used to directly save it's output (html string) into mongo.
Then after adding SSG, at the build time, the (consoled) fetched data appears as this.
Whereas simply fetching the api shows data correctly. here
Code of getStaticProps & getStaticPaths
export async function getStaticProps({ params }) {
try {
const { data } = await axios.post(baseUrl + getPostBySlug, { slug: params?.slug });
console.log({ slug: params?.slug }, 'data 2 ->', data); // here is the data consoled
return {
props: { post: data?.data ?? null },
revalidate: 10,
}
}
catch (err) {
return {
props: { post: null },
revalidate: 10,
}
}
}
export async function getStaticPaths() {
try {
const res = await fetch(baseUrl + getAllPosts, { method: 'GET' });
const data = await res?.json();
if (data?.success && data?.data) {
return {
paths: data?.data?.map(({ slug }) => ({ params: { slug } })),
fallback: true,
}
}
else {
return {
paths: [{ params: { slug: '/' } }],
fallback: true,
}
}
}
catch (err) {
return {
paths: [{ params: { slug: '/' } }],
fallback: true,
}
}
}
Final output, a SSG page but with no data init -> here
You need to update to Axios ^1.2.1 - there was an issue with previous versions.
You can set the headers as a temporary solution to prevent this from happening.
await axios.post("your/api/url",{
headers: { Accept: 'application/json', 'Accept-Encoding': 'identity' },
{ slug: "url-slug" }
)
I build an applicant with Redux RTK with createEntity
Two issue that I couldn't found it on the docs
CreateEntity is only return {ids: [], entities: []}? Is possible that return eg: totalPage from the response also?
Cache page only work on the hardcode initialState in createSlice if the pageQuery is same.
First question:
Getting the response from server was
{
users: [{id: 1}, ...]
totalPage: 100
}
I'd like to send totalPage to auto generated hook also.
export const usersAdapter = createEntityAdapter({})
export const initialState = usersAdapter.getInitialState()
export const usersApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUsers: builder.query({
query: (args) => {
return {
url: '/api/users',
method: 'GET',
params: { page: 1, limit: 10 }
}
},
validateStatus: (response, result) => {
return response.status === 200 && !result.isError
},
transformResponse: (responseData) => {
const loadedUsers = responseData?.users.map((user) => user)
console.log("responseData: ", responseData) // <----- return { users: [], totalPage: 100 }. Could we set this totalPage value into Adapter?
return usersAdapter.setAll(initialState, loadedUsers)
},
providesTags: (result, error, arg) => {
if (result?.ids) {
return [
{ type: "User", id: "LIST" },
...result.ids.map((id) => ({ type: "User", id })),
]
} else return [{ type: "User", id: "LIST" }]
},
})
})
})
Use the hook in component
const { data } = useGetUsersQuery("page=1&limit=10");
console.log(data) // { ids: [], entity: [{}, {}] };
// expected return { ids: [], entity: [{}, {}], totalPage: 100}
Second question:
Store the page query in createSlice. The edit page will be remain same after refresh if the page query value same as initialState value.
import { createSlice } from "#reduxjs/toolkit"
const userReducer = createSlice({
name: "user",
initialState: {
query: `page=1&limit=10`,
},
reducers: {
setUserPageQuery: (state, action) => {
const query = action.payload
state.query = query
},
},
})
Page url Flow:
localhost:3000/users > localhost:3000/users/4 > refresh -> data will remain after refresh browser. (query "page=1&limit10" same as createSlice initialState value )
localhost:3000/users > localhost:3000/users/15 > refresh -> data state will gone after refresh browser. (query "page=2&limit10" different from createSlice initialState value )
Appreciate all the reply :)
Created an initialState and will be updated the totalPage and currentPage after got the users list.
I found out onQueryStarted from docs, it able to update the store state in this method but only look like only for builder.mutation.
what's the correct way to get the user list and update the store page value in redux toolkit?
Listing two part of the code below:
apiSlice
component to use the hook
// 1. apiSlice
const usersAdapter = createEntityAdapter({})
export const initialState = usersAdapter.getInitialState({
totalPage: 0,
currentPage: 0,
})
export const usersApiSlice = apiSlice.injectEndpoints({
endpoints: (builder) => ({
getUsers: builder.query({ // <--- the docs are using builder.mutation, but i needed to pass params
query: (args) => {
const { page, limit } = args;
return {
url: `/api/users`,
method: "GET",
params: { page, limit },
}
},
validateStatus: (response, result) => {
return response.status === 200 && !result.isError
},
transformResponse: (responseData) => { // <<-- return { totalPages: 10, currentPage: 1, users: [{}] }
const loadedUsers = responseData?.users.map((user) => user)
return usersAdapter.setAll(initialState, loadedUsers)
},
async onQueryStarted(arg, { dispatch, queryFulfilled }) {
try {
const { data } = await queryFulfilled
const {totalPages, currentPage} = data; <----- totalPages & currentPage values are still 0 as initialState
dispatch(setPages({ currentPage, totalPages }))
} catch (error) {
console.error("User Error: ", error)
}
},
providesTags: (result, error, arg) => {
if (result?.ids) {
return [
{ type: "User", id: "LIST" },
...result.ids.map((id) => ({ type: "User", id })),
]
} else return [{ type: "User", id: "LIST" }]
},
})
})
});
export const {
useGetUsersQuery,
} = usersApiSlice
component to use the hook
Try to use the hook in user landing page
const UsersList = () => {
const { data: users, isLoading, isSuccess, isError } = useGetUsersQuery({page: 1, limit: 10 })
return (
<div>return the users data</div>
)
}
update the store value after get the data return
I've got the following function that gets triggered on a form submission
const [register, { loading }] = useMutation(RegisterDocument);
const router = useRouter();
const onSubmit = async (values: FormValues) => {
const v = { ...values };
delete v.confirmPassword;
const res = await register({
variables: { options: v },
update: (cache, { data }) => {
cache.writeQuery<MeQuery>({
query: MeDocument,
data: {
__typename: 'Query',
me: data?.register.user,
},
});
},
});
if (res.data?.register.user) {
router.push('/');
}
};
I then have the following test to submit the form
test('it should submit form without error', async () => {
const firstName = faker.name.firstName();
const surname = faker.name.lastName();
const username = faker.internet.userName().replace('#', '');
const email = faker.internet.email();
const password = faker.internet.password(6, false, /^[a-zA-Z0-9_.-]*$/);
const cache = new InMemoryCache().restore({});
const variables = {
options: { email, firstName, password, surname, username },
};
const user = { email, firstName, surname, username, id: 1, activated: false, photo: null };
const mocks = [
{
request: { query: RegisterDocument, variables },
result: { data: { register: { errors: null, user } } },
},
];
const { queryByTestId, container } = renderWithTheme(
<MockedProvider mocks={mocks} cache={cache}>
<Register />
</MockedProvider>,
);
await updateRegisterInputs(container); // util function that updates input values for submission
await submitForm({ queryByTestId, testId: 'register-submit', loadingTestId: 'register-loading' }); // util function that submits form
await waitFor(() => expect(onPush).toBeCalledWith('/'));
});
When I run this test res returns the following
{ data: { register: {} } }
However, once I remove the update property inside the register mutation function, res returns the following.
{ data: { register: { errors: null, user: [Object] } } }
Any ideas why the mocked return value returns an empty object for the register property only when the update property function is added?
Even just instantiating the update property like so;
update: () => {}
still breaks the response from the mutation.
I realised that the graphql doc required the __typename property in the relevant places in my mocks
So I have to update the mock to include the typenames.
const user = { email, firstName, surname, username, id: 1, activated: false, photo: null, __typename: 'User' };
const mocks = [
{
request: { query: RegisterDocument, variables },
result: { data: { register: { errors: null, user, __typename: 'UserResponse' } } },
},
];
I have been stuck on this concept for a while now. I need to update the 'votes' in an object such as this. What am I doing wrong?
export default function restaurantReducer(state = initialState.restaurants, action) {
switch(action.type) {
case 'UPDATE_RESTAURANT':
return [
...state,
{
...state[action.key],
['votes']: action.userName
}
];
default:
return state;
}
}
The data I have is
{
restaurants: {
ID: {
name : 'name',
votes : {
voterID: 'voters name',
voterID: 'voters name',
}
}
}
}
I would like to be able to add ID's and names to the votes...
initial-state.js is:
const initialState = {
auth: {
status: 'ANONYMOUS',
email: null,
displayName: null,
photoURL: null,
uid: null
},
messages: {
},
users: {
},
restaurants: {
},
};
export default initialState;