How can I route with array of objects in Next JS? - javascript

I've been struggling to route through pages using next js route query method. I was passing raw array of objects but it became empty in the page. I've been researching and I found a solution to use JSON.stringify(result) and parsing it in the other page with JSON.parse(query.result) and this worked. but when I use this approach on page reload the page crashes and the browser displays the following error.
This page isn’t workingIf the problem continues, contact the site owner.
HTTP ERROR 431
my code in the index.js is
<Link href={{
pathname: "/TvShows",
query: {
result: JSON.stringify(result),
//result: [result],
img: img,
index: index,
}}}
//as={"/TvShows"}
>
and the target page is Tvshows.js
first I defined a constants
const [result, setResult] = useState([]);
const [index, setIndex] = useState("");
const [img, setImg] = useState("");
const router = useRouter();
const query = router.query;
then
useEffect (()=>{
if(router.isReady){
//console.log(result);
const res = JSON.parse(query.result);
setResult(res);
setIndex(query.index);
setImg(query.img);
//console.log(res);
//router.isReady= false;
}
},[router.isReady])
the problem is when I stringily and parse these JSON. why is this happening?
and NOTE: in the url section of the page it uses the datas and it is super long.(maybe if that has an effect on it somehow). what is the best way to pass an array to a page?
the local data being passed in JSON.strimgify(result)
const Shows = [
{
id: 1,
title: "title1",
img: "imgURL",
desc: "ddescription1"
},
{
id: 2,
title: "title1",
img: "imgURL",
desc: "ddescription1"
},
{
id: 3,
title: "title1",
img: "imgURL",
desc: "ddescription1"
},
{
id: 4,
title: "title1",
img: "imgURL",
desc: "ddescription1"
},
] export default Shows;

Interestingly, I couldn't use the word 'code' as a query parameter in my project, so I renamed it to codeTerm. First, I suggest you to stay away some keywords like 'index' or 'code' etc.
In your TvShows component, try to console query object like below
import { withRouter } from 'next/router';
const TvShows = (props) => {
// the rest of your code
useEffect(() => {
console.log(props.router.query);
if (props.router.query.result)
console.log(JSON.parse(props.router.query.result));
}, [props.router]);
// the rest of your code
}
export default withRouter(TvShows);
You do not need that
const router = useRouter();
const query = router.query;
UPDATE
Can you try to route user using next/router instead of next/link?
import Router from 'next/router';
Router.push(
{
pathname: '/TvShows',
query: {
result: JSON.stringify(result),
img: img,
index: index,
},
}
);
This should give you what you want, here's the result

Related

Remove value from an array nested in an object

I have a problem with my code. I currently have some data like the one below;
users: [
{
name: 'bolu',
features: ['Tall'],
},
{
name: 'cam',
features: ['Bearded', 'Short'],
},
],
};
What I am trying to do is delete/remove a single feature - for example if I pass in 'short' into my redux action. I'd like for it (the 'Short' text) to be removed from the features array. I currently have my redux action set up this way:
export interface UsersDataState {
name: string,
features: Array<string>,
}
export interface UsersState {
users: UsersDataState[];
}
const initialState: UsersState = {
users: [],
};
export const usersSlice = createSlice({
name: 'users',
initialState,
reducers: {
removeUser: (state, action: PayloadAction<string>) => {
const removedUsers = state.users.filter((user) => user.features.indexOf(action.payload));
state.users = removedUsers;
},
},
});
So here I am passing in the value in (action.payload is the value being passed in). When this action is dispatched, I want to remove just the word that is passed in from the features array. I hope this is clearer now.
This doesn't work for some reason and I am unable to figure out why. Any help would be appreciated please, thank you.
You need to copy the objects on users and filter on features.
Here an example:
var users = [{
name: 'bolu',
features: ['Tall'],
}, {
name: 'cam',
features: ['Bearded', 'Short'],
}];
const payload = "Short";
const newUsers = users.map(user => ({ ...user,
features: user.features.filter(f => f != payload)
}));
console.log(newUsers);
Currently you are filtering users array but you should be filtering nested features array.
Try this
const removedUsers = state.users.map(user => {
return {...user, features: user.features.filter(feature => feature !== action.payload)};
})

How to enrich data from custom react hook

In my React application I have created a custom hook which returns a set of data wherever used.
It's used like const projects = useProjects();
It's an array of objects , we can assume it looks like this :
[{project_id : 123 , name : 'p1'} , {project_id : 1234 , name : 'p2'} ]
Now I need to enrich this data with data from an API. So i have to loop through projects and basically add a new field to each object, so the new array of objects will look like this :
[{project_id : 123 , name : 'p1' field3: 'api data'} , {project_id : 1234 , name : 'p2' , field3: 'api data1' } ]
How can I achieve this ?
What I did was loop through the projects data and directly added the field inside the loop. But I dont know if i should be mutating this data like that ? I was hoping to see if this is good practice or not.
There's a few ways you could solve this - it all depends on how you're getting the data back from the API. If you want to have that injected into the hook, you could do something like this -
const DEFAULT_PROJECTS = [
{ project_id : 123, name: 'p1' },
{ project_id : 1234, name: 'p2' },
];
const useProjects = (dataFromApi) => {
// Assuming that dataFromApi is what you got back from your API call,
// and it's a dictionary keyed on the project_id.
return useMemo(() => {
return DEFAULT_PROJECTS.map(proj => {
const extraData = dataFromApi.get(proj.project_id) || {};
return {
...proj,
...extraData,
};
});
}, [dataFromApi]);
};
The useMemo here isn't super helpful if the dataFromApi is always changing - it will just rebuild the returned object every time.
If you wanted to get the data as part of your hook, you do something like this -
import { useEffect, useMemo, useState } from 'react';
const DEFAULT_PROJECTS = [
{ project_id : 123, name: 'p1' },
{ project_id : 1234, name: 'p2' },
];
const useProjects = () => {
const [dataFromApi, setDataFromApi] = useState(null);
useEffect(() => {
if (!!dataFromApi) return;
// Simulate the data fetch
const fetchData = async () => {
return new Promise(resolve => {
setTimeout(() => {
const map = new Map();
map.set(123, {
field3: 'api data',
field4: 'other data',
});
setDataFromApi(map);
}, 2000);
});
};
fetchData();
}, [dataFromApi]);
return useMemo(() => {
let extraData = dataFromApi || new Map();
return DEFAULT_PROJECTS.map(proj => {
const extraFields = extraData.get(proj.project_id) || {};
return {
...proj,
...extraFields,
};
});
}, [dataFromApi]);
}
export default useProjects;
Here's a code sandbox that shows it in action.

Next.js: getStaticPaths for nested dynamic routes data structure error

I have a page [categories][price].js and im trying to achieve the data structure in getStaticPaths e.g
cat1/10 cat1/20 cat1/30 cat1/40 cat2/10 cat/20 etc
I have looked at this post: Next.js: getStaticPaths for nested dynamic routes as it's the same error but as their data structure is a bit different I'm not sure how to translate this to my example
It looks like im mapping the data incorrectly as I get the following error when trying to create my dynamic routes.
Error: Additional keys were returned from `getStaticPaths` in page "/[catSlug]/[price]". URL Parameters intended for this dynamic route must be nested under the `params` key, i.e.:
return { params: { catSlug: ..., price: ... } }
Keys that need to be moved: 0, 1.
How can I correctly map my data?
[categories][price].js
export async function getStaticPaths() {
const prices = [' 10', ' 20', ' 30']
const categories = [{ name: 'cat' }, { name: 'cat2' }, { name: 'cat3' }]
const paths = categories.map(({ slug }) =>
prices.map((price) => ({ params: { catSlug: slug, price: price } }))
)
return {
paths,
fallback: false
}
}
flatten the array
const paths = categories.map(({ name }) =>
prices.map((price) => ({ params: { catSlug: name, price: price } }))
).flat()

Passing Username and UserID Parameter to WebChat using WebChat Hooks API

I used to be able to pass the Username and UserID parameter from the URI using the below code on Webchat:
var queryString = window.location.search;
var urlParams = new URLSearchParams(queryString);
var user = urlParams.get('userid')
var usern = urlParams.get('username')
and I pass it on to the Webchat using the below code:
window.WebChat.renderWebChat({
directLine: window.WebChat.createDirectLine({ token: }),
store,
userID: user,
username: usern,
styleOptions
}, document.getElementById('webchat'));
document.querySelector('#webchat > *').focus();
Now this works perfectly before when I was using the usual Webchat for the Botframework. Its no longer working when I started using ReachJS on the Webchat. How do I pass this parameter using the Webchat Hooks API? I tried specifying it using the below code but does not work.
ReactDOM.render(
<Composer directLine={window.WebChat.createDirectLine({ token: })}>
<BasicWebChat />
<SendMessageOnConnect />
<user />
<usern />
</Composer>,
document.getElementById('webchat')
);
This works in my React project. You're implementation is different, but this should put you in the right direction. You can see in the listed activity that the user name is updated to 'Steve'. In my case, id is not updated because I am generating an id with the token. When an id is generated via Direct Line with the token, it takes precedence over any id's passed via Web Chat.
import React from 'react';
import ReactWebChat, { createDirectLine } from 'botframework-webchat';
export default class WebChatView extends React.Component {
constructor(props) {
super(props);
this.state = {
user: '',
usern: ''
};
}
componentDidMount() {
var queryString = window.location.search;
var urlParams = new URLSearchParams(queryString);
var user = urlParams.get('userid');
var usern = urlParams.get('username');
this.setState({ user: user, usern: usern })
this.fetchToken();
}
async fetchToken() {
const res = await fetch('http://localhost:3500/directline/token', { method: 'POST' });
const { token } = await res.json();
this.setState(() => ({
directLine: createDirectLine({ token: token })
}));
}
render() {
return (
this.state.directLine ?
<ReactWebChat
directLine={this.state.directLine}
userID={this.state.user}
username={this.state.usern}
/>
:
<div>Connecting to bot…</div>
)
}
}
Activity output:
{
type: 'message',
id: '4wpfp......-f|0000002',
timestamp: 2020-09-02T21:39:01.197Z,
serviceUrl: 'https://directline.botframework.com/',
channelId: 'directline',
from: { id: 'dl_15990824712200.ruhpue7p1j', name: 'Steve', role: 'user' },
conversation: { id: '4wpfp......-f' },
recipient: { id: 'botberg#QaeuoeEamLg', name: 'Bot' },
textFormat: 'plain',
locale: 'en-US',
text: 'Hi',
entities: [
{
type: 'ClientCapabilities',
requiresBotState: true,
supportsListening: true,
supportsTts: true
}
],
channelData: {
clientActivityID: '1599082740974mexnvax1jq',
clientTimestamp: '2020-09-02T21:39:00.974Z'
},
rawTimestamp: '2020-09-02T21:39:01.1971653Z',
callerId: 'urn:botframework:azure'
}
Hope of help!
You can try with useParams() hook instead as:
let { userid, username } = useParams();
Or rename as the following:
let { userid: user, username: usern } = useParams();
Read further in the documentation here which states:
useParams returns an object of key/value pairs of URL parameters. Use it to access match.params of the current <Route>.
Or you can also use useLocation() hook as:
const { search } = useLocation();
const { userid, username } = search;
Read from the documentation:
The useLocation hook returns the location object that represents the current URL. You can think about it like a useState that returns a new location whenever the URL changes.

Redux-Toolkit and React Hooks - Store change does not trigger re-render

I am trying to pre-populate a form with information from the database whenever the URL contains a query parameter with an ID. I am unable to make the site trigger a re-render when the information is fetched from the database. The relevant code in the component is shown below.
let { id } = useParams();
const { title, summary, severity, references, type, vulnerabilities } = useSelector(
(state: RootState) => state.articles.article
)
useEffect(() => {
if(id) dispatch(fetchArticle(id))
}, [])
const [form, setForm] = useState<FormState>({
title: title,
type: type,
summary: summary,
severity: severity,
references: references,
vulnerabilities: vulnerabilities,
autocompleteOptions: autocompleteSuggestions,
reference: "",
vulnerability: "",
})
useEffect(() => {
setForm({
...form,
title: title,
summary: summary,
severity: severity,
references: references,
type: type,
vulnerabilities: vulnerabilities
})
}, [title, summary, severity, references, type, vulnerabilities])
We can see that the Redux action is fired and the article state is updated in the store. I have also tried to console.log inside the hook to verify that it runs, which it does, but only on the initial render. If I change initialState in the slice, then it is reflected in the form.
let initialState: ArticleState = {
loading: false,
error: null,
article: {
title: "",
severity: 0,
type: 0,
summary: "",
references: [],
vulnerabilities: [],
id: 0
},
articles: [] as Article[],
autocompleteSuggestions: [] as DropdownItem[]
}
const ArticleSlice = createSlice({
name: "articles",
initialState,
reducers: {
getArticleStart: startLoading,
getArticleFailure: loadingFailed,
getArticleSuccess(state: ArticleState, { payload }: PayloadAction<Article>) {
state.article = payload
state.error = null
state.loading = false
}
}
})
export const {
getArticleFailure,
getArticleStart,
getArticleSuccess
} = ArticleSlice.actions
export default ArticleSlice.reducer
Weirdly enough, if I save the code while on the page the hot-reloading does update it and triggers a re-render, populating the form correctly.
Note that I am using Redux-Toolkit, hence the slice syntax.
I'm not promising anything but try this, see if it works:
useEffect(()=>{
(async () => {
if (id) dispatch(fetchArticle(id));
await setForm({
...form,
title: title,
summary: summary,
severity: severity,
references: references,
type: type,
vulnerabilities: vulnerabilities
})
})();
}, []);
Then remove the second useEffect. If this doesn't work, can we see your render jsx code?

Categories