I’m making a fetch request that sends back a JSON with an Array of Documents and inside the array of Documents I get another array of "Keywords". I am able to save the Documents array with React Context but I get an error when trying to save the Keywords array. The error I get is the following: "Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘Keywords’)".
This is an example of the response I get so you can see the structure of the JSON:
Here is my code:
Dashboard.jsx -> Here is where I make the fetch request.
import { useEffect } from "react";
import { useWorkViewContext } from "../hooks/useWorkViewContext";
function Dashboard({ user }) {
const { workview, keywords, dispatch } = useWorkViewContext();
useEffect(() => {
const fetchWorkView = async () => {
const credentials =
import.meta.env.VITE_SERVICE_USER +
":" +
import.meta.env.VITE_SERVICE_PASSWORD;
const response = await fetch(
"https://urlforfetch.com",
{
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${credentials}`,
},
body: JSON.stringify({
WorkViewApplication: "VAPR",
WorkViewClassName: "Policy",
WorkViewFilter: "All Policy Record",
SearchAttributes: [
{
Name: "InsuranceCarrier",
Value: "MAPFRE",
},
],
}),
}
);
const json = await response.json();
if (response.ok) {
localStorage.setItem("workview", JSON.stringify(json.Documents));
localStorage.setItem(
"keywords",
JSON.stringify(json.Documents[0].Keywords)
);
dispatch(
{ type: "SET_WORKVIEW", payload: json.Documents },
{
type: "SET_KEYWORDS",
payload: JSON.stringify(json.Documents[0].Keywords),
}
);
}
};
if (user) {
fetchWorkView();
}
}, [dispatch, user]);
return (
<main>
<div className="dashboard">
<h1>
Welcome back, <span className="accent">{user.username}</span>
</h1>
<div className="grid-sm">
<div className="grid-sm">
<p>In this section you will find you cases information.</p>
</div>
<div className="grid-lg">
<h2>My Cases</h2>
{workview && workview.length > 0 && (
<div className="grid-md">
{workview.map((document, index) => (
<>
<a key={index} href={document.DocumentURL}>
{document.DocumentName}
</a>
</>
))}
</div>
)}
{keywords && keywords.length > 0 && (
<div className="grid-md">
{keywords.map((keyword, index) => (
<>
<a key={index}>{keyword.Name}</a>
</>
))}
</div>
)}
</div>
</div>
</div>
</main>
);
}
export default Dashboard;
WorkViewContext.jsx
import { createContext, useReducer } from "react";
export const WorkViewContext = createContext();
export const workviewReducer = (state, action) => {
switch (action.type) {
case "SET_WORKVIEW":
return {
workview: action.payload,
};
case "SET_KEYWORDS":
return {
keywords: action.payload,
};
default:
return state;
}
};
export const WorkViewContextProvider = ({ children }) => {
const [state, dispatch] = useReducer(workviewReducer, {
workview: null,
keywords: null,
});
return (
<WorkViewContext.Provider value={{ ...state, dispatch }}>
{children}
</WorkViewContext.Provider>
);
};
Using the save to local storage function I was able to save the Documents[0].Keywords array but I can’t save it into the React Context. In this example I saved Keywords array of the first record of Documents but the end result is to save all the keywords records of all the documents records.
const json = await response.json();
if (response.ok) {
localStorage.setItem("workview", JSON.stringify(json.Documents));
localStorage.setItem(
"keywords",
JSON.stringify(json.Documents[0].Keywords)
);
dispatch(
{ type: "SET_WORKVIEW", payload: json.Documents },
{
type: "SET_KEYWORDS",
payload: JSON.stringify(json.Documents[0].Keywords),
}
);
}
The purpose of this is to use the Keywords array to create a table were the Keywords Name is the Column Name and the Keywords Value is the table data.
Can someone tell me what I’m doing wrong?
2
Answers
Here’s what you dispatch as
keywords
:This is a
string
(JSON.stringify
), not anArray
.You then try to iterate over
keywords
:As
keywords
is astring
, there’s nothing tomap
.If I had to bet, your solution would be to dispatch the array itself instead:
The issue seems to be with how you are calling the
dispatch
function when updating thekeywords
state in yourworkviewReducer
. You are passing two separate objects to thedispatch
function, which is not the correct way to update multiple state properties at once usinguseReducer
.Here’s how you can fix it:
Dashboard.jsx
to the following:workviewReducer
to accept thekeywords
property in the payload:This way, you can pass both the
workview
andkeywords
properties in the same payload object and update them in a single call todispatch
.It seems like you’re trying to store the
keywords
array in local storage, but you are not retrieving it in your code. If you want to use thekeywords
array from local storage, you can add the following line after retrieving theworkview
array from local storage:Then you can use
keywordsFromStorage
instead ofjson.Documents[0].Keywords
in yourdispatch
call.