I am using axios to get an array from a JSON file and I want to use the same array over multiple nodes / pages.
Currently I'm using this on each page var printers = GetPrinters();
I was trying call GetPrinters()
from the App.tsx and pass it to each page via a router but I couldn't seem to get that to work. Is there a way I can store the array on state and access it on any node?
I plan to make 4 more pages similar to MonoPrints.tsx that all need access to the data from the array, they won't be updating the array at all, just accessing it.
I would like to use the best practice for this kind of thing and am stuck with repeating the call for each page at the moment.
Site Structure: App.tsx
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { TonerLevels } from "./pages/TonerLevels";
import { MonoPrints } from "./pages/MonoPrints";
import { MonoCopies } from "./pages/MonoCopies";
import { ColourPrints } from "./pages/ColourPrints";
import { ColourCopies } from "./pages/ColourCopies";
export function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/TonerLevels" element={<TonerLevels />}></Route>
<Route path="/MonoPrints" element={<MonoPrints />}></Route>
<Route path="/MonoCopies" element={<MonoCopies />}></Route>
<Route path="/ColourPrints" element={<ColourPrints />}></Route>
<Route path="/ColourCopies" element={<ColourCopies />}></Route>
</Routes>
</BrowserRouter>
);
}
Pages/ TonerLevels
export function TonerLevels() {
var printers = GetPrinters();
return (
<div>
<Nav></Nav>
<table className="table table-dark table-hover">
<thead>
<tr>
<th>Location</th>
<th>IP</th>
<th>Name</th>
<th>Serial</th>
<th>Black %</th>
<th>Yellow %</th>
<th>Magenta %</th>
<th>Cyan %</th>
<th>K1 %</th>
<th>K2 %</th>
<th>Current Monthly Prints</th>
<th>Current Monthly Copies</th>
</tr>
</thead>
<tbody className="table-group divider">
{printers
? printers.map((printer) => {
return (
<tr key={printer.address}>
<td>{printer.location}</td>
<td>
<a
href={"//" + printer.address}
target="_blank"
rel="noopener noreferrer"
>
{printer.address}
</a>
</td>
<td>{printer.name}</td>
<td>{printer.serial}</td>
<td>{printer.black > -1 ? printer.black : ""}</td>
<td>{printer.yellow > -1 ? printer.yellow : ""}</td>
<td>{printer.magenta > -1 ? printer.magenta : ""}</td>
<td>{printer.cyan > -1 ? printer.cyan : ""}</td>
<td>{printer.k1 > -1 ? printer.k1 : ""}</td>
<td>{printer.k2 > -1 ? printer.k2 : ""}</td>
<td>{getPrints(printer)}</td>
<td>{getCopies(printer)}</td>
</tr>
);
})
: null}
</tbody>
</table>
</div>
);
}
Services/ PrinterServices
import axios from "axios";
import { useEffect, useState } from "react";
const PRINTER_REST_API_URL = "http://localhost:8080/GetReport";
export interface Printer {
address: string;
black: number;
monoCopies: number;
monoPrints: number;
colourCopies: number;
colourPrints: number;
cyan: number;
k1: number;
k2: number;
location: string;
magenta: number;
name: string;
serial: string;
yellow: number;
Reports: [
{
month: string;
monoPrints: number;
monoCopies: number;
colourPrints: number;
colourCopies: number;
}
];
}
export function GetPrinters() {
const [printers, setPrinters] = useState<Printer[] | null>();
useEffect(() => {
axios.get(PRINTER_REST_API_URL).then((response) => {
setPrinters(response.data);
});
}, []);
return printers;
}
EDIT: Typescript of the code that worked from serod:
const Context = createContext<Printer[] | undefined>(undefined);
interface ContextProviderProps {
children: ReactNode;
}
export const ContextProvider: React.FC<ContextProviderProps> = ({
children,
}) => {
const [printers, setPrinters] = useState<Printer[]>();
useEffect(() => {
axios.get(PRINTER_REST_API_URL).then((response) => {
setPrinters(response.data);
});
}, []);
return <Context.Provider value={printers}>{children}</Context.Provider>;
};
You can use "React Context" to store the array on a global state and then access it from any component.
Context code would look like this in Javascript:
import React, { useState, createContext, useEffect } from "react";
import axios from "axios";
const Context = createContext();
export const ContextProvider = ({ children }) => {
const [printers, setPrinters] = useState();
useEffect(() => {
axios.get("PRINTER_REST_API_URL").then((response) => {
setPrinters(response.data);
});
}, []);
return (
<Context.Provider
value={{
printers,
}}
>
{children}
</Context.Provider>
);
};
export default Context;
Then add ContextProvider in your app.js
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { TonerLevels } from "./pages/TonerLevels";
import { MonoPrints } from "./pages/MonoPrints";
import { MonoCopies } from "./pages/MonoCopies";
import { ColourPrints } from "./pages/ColourPrints";
import { ColourCopies } from "./pages/ColourCopies";
export function App() {
return (
<ContextProvider>
<BrowserRouter>
<Routes>
<Route path="/TonerLevels" element={<TonerLevels />}></Route>
<Route path="/MonoPrints" element={<MonoPrints />}></Route>
<Route path="/MonoCopies" element={<MonoCopies />}></Route>
<Route path="/ColourPrints" element={<ColourPrints />}></Route>
<Route path="/ColourCopies" element={<ColourCopies />}></Route>
</Routes>
</BrowserRouter>
</ContextProvider>
);
}
Now you can simply use useContext
hook to access the printers state from any component.