This is my first time using useRouter and i really dont know how it works.
I want to take props.indexUrl and added dynamiacally into the url below, i have done several ways but always getting error.
import { useRouter } from "next/router";
const Component = () => {
const router = useRouter();
const {
query: { indexUrl },
} = router;
const props = {
indexUrl,
};
return props.indexUrl;
};
export const urls = [
{
url:
"click.myyellowlocal.com/k.php?ai=19202&url=http%3a%2f%2f" +
Component,
},
{
url: "cse.google.vu/url?q=https%3A%2F%2",
},
{
url: "sazhs.co.kr/member/login.html?noMemberOrder=&returnUrl=http%3a%2f%2",
},
];
I have try like this before
import { useRouter } from "next/router";
const router = useRouter();
const {
query: { indexUrl },
} = router;
const props = {
indexUrl,
};
export const urls = [
{
url:
"click.myyellowlocal.com/k.php?ai=19202&url=http%3a%2f%2f" +
props.indexUrl,
},
{
url: "cse.google.vu/url?q=https%3A%2F%2",
},
{
url: "sazhs.co.kr/member/login.html?noMemberOrder=&returnUrl=http%3a%2f%2",
},
];
and give an error Cannot read properties of null (reading 'useContext')
so i make like this
const Component = () => {
const router = useRouter();
const {
query: { indexUrl },
} = router;
const props = {
indexUrl,
};
};
but i dont know how to get props.indexUrl to url like in the top code.
more detail, the router indexUrl is from other file
function sendProps() {
Router.push({
// pathname: "/processUrl",
pathname: "/urlList",
query: { indexUrl },
});
}
how to get the value of props.indexUrl and add it into the list of url dynamiacally ??
Related
I am failing to get dynamic data from firestore using getStaticPaths in nextjs. When I render the data from firestore using getStaticProps, it works, but when I open a specific item to get its details, it refuses and gives me a 404 page. This is what my code looks like for now, the [id].js page.
import React from 'react'
import { db } from '#/Firebase';
import {collection, getDoc} from "firebase/firestore";
const reference = collection(db, "abantu");
export const getStaticProps = async (context) => {
const id = context.params.id;
const data = await getDoc(reference);
const umuntuData = fetch(`${data}` + id);
return {
props: {
umuntu: umuntuData
}
}
}
export const getStaticPaths= async () => {
const umuntu = await getDoc(reference);
// const umuntuData = umuntu.docs
const paths = umuntu.docs.map(doc => {
return {
params: { id: doc.id }
}
})
return {
paths,
fallback: false
}
}
function Details({umuntu}) {
return (
<div>
<h1>{umuntu.ibizo}</h1>
</div>
)
}
export default Details
Where could I be going wrong?.
Your query getDoc(specific doc) vs getDocs(list of docs)
export const getStaticPaths= async () => {
const umuntu = await getDocs(reference);
// const umuntuData = umuntu.docs
const paths = umuntu.docs.map(doc => {
return {
params: { id: doc.id }
}
})
return {
paths,
fallback: false
}
}
For your static props, you will need to get specific document
//import {doc} from "firebase/firestore";
export const getStaticProps = async (context) => {
const id = context.params.id;
const docRef = doc(db, "abantu", id);
const data = await getDoc(docRef);
const umuntuData = fetch(`${data}` + id);
return {
props: {
umuntu: umuntuData
}
}
}
I am trying to get a dynamic title for useMeta with composition API but it does not work.
<script setup>
import { computed } from 'vue'
import { POST } from '#/constants/blog'
import { useQuery, useResult } from "#vue/apollo-composable";
import { useRoute } from 'vue-router'
import { useMeta } from "vue-meta";
const route = useRoute();
const variables = computed(() => ({
slug: route.params.slug,
}));
const { result, loading, error } = useQuery(
POST, variables
);
const post = useResult(result, null, data => data.post.data );
const metaTitle = computed(() => ({
title: post.attributes.title,
}));
useMeta(metaTitle);
</script>
here is the response
{
"data": {
"post": {
"data": {
"id": 4,
"attributes": {
"title": "This is the post title"
}
}
}
}
}
Please help me understand what is wrong here!
Maybe It's too late to answer this question.
This module is for vue2. After many searches, I found version 3 of this module, But It's at the alpha stage, now.
I found an alternative solution that doesn't need any dependency.
Create a new file somewhere in your project directory(utils.js) and put the below code in it:
const changeMetaTags = (meta) => {
document.title = `${meta.title} - YOUR PROJECT NAME`;
// document.querySelector('meta[name="og:title"]').setAttribute("content", meta['og:title']);
// document.querySelector('meta[name="description"]').setAttribute("content", meta.description);
// document.querySelector('meta[name="og:description"]').setAttribute("content", meta['og:description']);
// document.querySelector('meta[name="keywords"]').setAttribute("content", meta.keywords);
}
export { changeMetaTags }
Caution: You have to have the above code on your index.html file.
and for your use case just import it and use:
<script setup>
import { computed } from 'vue'
import { POST } from '#/constants/blog'
import { useQuery, useResult } from "#vue/apollo-composable";
import { useRoute } from 'vue-router'
import { useMeta } from "vue-meta";
import { changeMetaTags } from "#/infrastructures/seo/utils"; // <----- this
const route = useRoute();
const variables = computed(() => ({
slug: route.params.slug,
}));
const { result, loading, error } = useQuery(
POST, variables
);
const post = useResult(result, null, data => data.post.data );
const metaTitle = computed(() => ({
title: post.attributes.title,
}));
changeMetaTags(metaTitle.value); // <---- this
</script>
I use it in the router file (router/index.js) as well
const router = createRouter({
routes: [
{
path: "/",
component: () => import("#/layouts/MainLayout.vue"),
children: [
{
path: "",
name: "Home",
meta: { // <-------- add this
title: "Home",
description:
"your description",
"og:title": `YOUR PROJECT NAME home page`,
"og:description":
"og description",
keywords:
`your, keywords`,
},
component: () => import("#/views/HomeView.vue"),
},
...
]
})
router.beforeEach((to, from) => {
changeMetaTags(to.meta); // <----- and this
...
})
How do I use getStaticPaths when using Redux with Next.js?
I am using next-redux-wrapper to store my content and i am having trouble getting the data to display.
Please see my code example below
import { useSelector } from "react-redux";
import {getPageData} from '../redux/actions/pages'
import { useRouter } from "next/router";
import {wrapper} from '../redux'
import { getNavItems } from '../redux/actions/navItems';
import { getServiceData } from '../redux/actions/services';
import { getHomePage } from '../redux/actions/homePage';
export default function pageTemplate({page}) {
return(
<h1>{page.title}</h1>
)
}
export const getStaticPaths = async () => {
const pages = await getPageData()
const paths = Object.keys(pages).map((key) => {
const page = pages[key]
return{
params: {slug: page.slug.current}
}
})
return{
paths,
fallback: false
}
}
export const getStaticProps = wrapper.getStaticProps((store) => async (context) => {
await store.dispatch(getHomePage());
await store.dispatch(getServiceData());
await store.dispatch(getNavItems());
const slug = context.params.slug
console.log(slug)
const page = await store.dispatch(getPageData(slug))
return {
props: {page},
revalidate: 60
};
}
You can also see my redux action which is working fine as I have tested it in the sanity.io groq playground.
import * as actionTypes from '../actions/actionTypes';
import { groq } from 'next-sanity';
import { getClient } from '../../lib/sanity.server';
export const getPageData = (slug) => async (dispatch) => {
const query = groq`
*[_type == "page"]{
_id,
title,
slug
}
`;
const queryTwo = groq`
*[_type == "page" && slug.current != $slug]{
_id,
title,
slug
}
`;
if(slug) {
try {
// const client = ...
const pageData = await getClient().fetch(query);
dispatch({
type: actionTypes.GET_ALL_PAGES,
payload: pageData
});
} catch (err) {
console.log(err);
}
}
try {
// const client = ...
const pageData = await getClient().fetch(queryTwo);
dispatch({
type: actionTypes.GET_ALL_PAGES,
payload: pageData || pagesData
});
} catch (err) {
console.log(err);
}
};
I have faced the same issue before just releasing that you can use getStaticPaths without the need of the next-redux-wrapper
here is some example from a code that I've been working on lately
import { ReduxWrapper, store } from '#store/store'
export const getStaticPaths = async () => {
const postsSlugs = store
.getState()
.posts.posts.map((post) => ({ params: { slug: post.slug } }))
return {
paths: postsSlugs,
fallback: true,
}
}
export const getStaticProps = ReduxWrapper.getStaticProps(
(store) => async (context) => {
const slug = context.params?.slug
const post = store.getState().posts.post
return {
props: { post },
}
},
)
I hope that it may help you or anyone searching for the same issue
I'm trying to figure out how to use the useNavigate hook to navigate/redirect a user and update the query params, if there are any.
I've created a custom useNavigateParams hook that I've adapted from several different SO answers and it looks like this:
import { generatePath, ParamKeyValuePair, useNavigate } from 'react-router-dom';
import { getSearchParams, isObjectEmpty } from 'src/utils';
type TUseNavigateParams = {
uri: string;
params?: Record<string, unknown>;
};
export default function useNavigateParams() {
const navigate = useNavigate();
return ({ uri, params = {} }: TUseNavigateParams) => {
let path = uri;
if (!isObjectEmpty(params)) {
path += generatePath('?:queryString', {
uri,
queryString: getSearchParams(Object.entries(params) as ParamKeyValuePair[]),
});
}
console.log('decoded', decodeURIComponent(path));
navigate(path);
};
}
const getSearchParams = (params: ParamKeyValuePair[]) => {
let searchParams = '';
params.forEach((param, index) => {
const localDestructured = Object.entries(param[1]);
console.log('localDestructured', localDestructured);
searchParams += createSearchParams({
[param[0]]: JSON.stringify({ [localDestructured[0][0]]: localDestructured[0][1] }),
});
});
return createSearchParams(searchParams).toString();
};
The idea here is that I would essentially always use useNavigateParams throughout my project, instead of useNavigate.
My issue is the following. Something simple like the following would work fine:
const uri = 'myPath'
const filter = 'active'
const params = { filter: { status: filter } }
navigate({
uri,
params,
})
This would print,
myPath?filter={"status":"active"}
but doing something like,
const uri = 'myPath'
const filter = 'active'
const params = { filter: { status: filter, hello: 'world' } }
navigate({
uri,
params,
})
would not print,
myPath?filter={"status":"active", "hello":"world"}
I understand that I could add another forEach or figure out some hacky approach, but it just seems so bulky as it is and it is effectively in no way reusable/dynamic.
I'd like to be able to do pass in some sort of params, such as,
const uri = 'myPath'
const filter = 'active'
const params = { filter: { status: filter, hello: 'world' }, foo: 'bar', baz: { node: 'leaf' } }
navigate({
uri,
params,
})
and expect the output to be:
myPath?filter={"status":"active", "hello":"world"}&foo=bar&baz={"node":"leaf"}
Is there a cleaner and more dependable approach to achieve such a result?
I was already using axios, so I ended up using getUri:
import axios from 'axios';
import { useNavigate } from 'react-router-dom';
type TUseNavigateParams = {
uri: string;
params?: Record<string, unknown>;
};
export default function useNavigateParams() {
const navigate = useNavigate();
return ({ uri, params = {} }: TUseNavigateParams) => {
const path = axios.getUri({ url: uri, params });
navigate(path);
};
}
created state to store the ipaddress
auth.js
const state = {ipAddress: ''}
const getters = {ipAddress: (state) => {
return state.ipAddress
}
}
const actions = {
async getIpAddress ({commit}) {
const { data: { ip } } = await axios.get("https://www.cloudflare.com/cdn-cgi/trace", {responseType: "text", transformResponse: data =>
Object.fromEntries(data.trim().split("\n").map(line => line.split("=")))
});
commit('setIp', ip)},
}
here is the ip address
const mutations = {
setIp(state, payload) {
state.ipAddress = payload
},}
App.vue
Calling the fucntion ...
<script>
import { mapActions, mapState, mapGetters } from "vuex";
Vue.mixin(windowMixin)
export default {
name: "App",
methods: {
...mapActions('auth',['getIpAddress']),
},
mounted() {
this.getIpAddress();
},
};
</script>
product.service.js
sending the ip as a parameters
import ApiService from "../api.service";
const ProductService = {
async productDetails(productID,ipAddress){
const requestData = {
method: 'get',
url: `/api/products/v1/product/detail/?itemId=${productID}`,
params: {
detailToken: localStorage.getItem('detailData') && localStorage.getItem('detailData'),
ip: ipAddress
}
}
Here I added this ipAddress to productDetails in another Component,
but I want to import it in product.service.js directly, Please help me !