У меня есть следующий компонент входа в приложение:
React.useEffect(() => {
const fetchData = async () => {
try {
const libraries: unknown[] = await sendRequest('/libraries');
const softwareComponents: unknown[] = await sendRequest('/softwareComponents');
localStorage.setItem('libraries', JSON.stringify(arraySetup(libraries, 'libraries')));
localStorage.setItem('softwareComponents', JSON.stringify(arraySetup(softwareComponents, 'software-components')));
} catch (err) {
console.error(err);
}
};
isAuthenticated() && fetchData();
}, []);
Я извлекаю массивы из двух конечных точек, а затем устанавливаю результат в локальное хранилище, чтобы я мог читать его в других компонентах.
Дочерний компонент использует данные следующим образом:
const [data, setData] = React.useState<Array<any>>([]);
React.useEffect(() => {
const libraries = getLocalStorageItem('libraries');
const softwareComponents = getLocalStorageItem('softwareComponents');
const condition = libraries && softwareComponents;
if (condition) {
setData([...libraries, ...softwareComponents]);
}
}, []);
const getDataLength = (category: string) => {
return (data || []).filter((item: any) => item.category === category).length;
};
return (
<React.Fragment>
<OwcGrid item xs = {12} s = {4}>
<LibrariesCard numberOfElements = {getDataLength('libraries')} /> // rendering here the length of the localStorage item.
</OwcGrid>
Цель/вызов:
Я хочу использовать React.Context для удаления реализации локального хранилища, но я не уверен, как сделать это максимально простым.
Я видел только руководства, которые реализовывали действия отправки и т. д., но это кажется уже слишком сложным, потому что я только извлекаю данные и не изменяю их, поскольку я только визуализирую их.
Есть ли советы или руководства, как начать с этого?





Возможная реализация с контекстом:
//context.tsx
import {
createContext,
ReactNode,
useContext,
useEffect,
useMemo,
useState,
} from 'react';
export interface LibsAndComponentsInterface {
data: unknown[];
}
const LibsAndComponentsContext = createContext<
LibsAndComponentsInterface | undefined
>(undefined);
// Wrap your App component with this
export function LibsAndComponentsProvider({
children,
}: {
children: ReactNode;
}) {
const [libs, setLibs] = useState<unknown[]>([]);
const [components, setComponents] = useState<unknown[]>([]);
useEffect(() => {
const fetchData = async () => {
try {
const libraries: unknown[] = await sendRequest('/libraries');
const softwareComponents: unknown[] = await sendRequest(
'/softwareComponents'
);
setLibs(libraries);
setComponents(softwareComponents);
} catch (err) {
console.error(err);
}
};
isAuthenticated() && fetchData();
}, []);
const ctxValue = useMemo(
() => ({
data: [...libs, ...components],
}),
[libs, components]
);
return (
<LibsAndComponentsContext.Provider value = {ctxValue}>
{children}
</LibsAndComponentsContext.Provider>
);
}
export function useLibsAndComponents() {
const ctx = useContext(LibsAndComponentsContext);
if (ctx == null) {
throw new Error(
'useLibsAndComponents must be inside LibsAndComponentsProvider'
);
}
return ctx;
}
// later in your components
const { data } = useLibsAndComponents()
Вот полная настройка React Context. Пожалуйста, используйте машинописный текст, если это необходимо.
MyContextProvider.js
const { createContext, useState } = require("react");
//Create a context
export const Mycontext = createContext();
//Created a component that helps to provide the context.
const MyContextProvider = ({ children }) => {
//Declare all the states that you need
const [libraries, setLibraries] = useState([]);
const [softwareComponents, setSoftwareComponents] = useState([]);
return (
<Mycontext.Provider
//provide all the state, function as value that you need in any child component
value = {{
libraries,
setLibraries,
softwareComponents,
setSoftwareComponents
}}
>
{children}
</Mycontext.Provider>
);
};
export default MyContextProvider;
index.js
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import MyContextProvider from "./MyContextProvider";
import App from "./App";
const rootElement = document.getElementById("root");
const root = createRoot(rootElement);
//Wrap App component By the MycontextProvider component
root.render(
<StrictMode>
<MyContextProvider>
<App />
</MyContextProvider>
</StrictMode>
);
App.js
import { useContext } from "react";
import ChildComponent from "./Child";
import { Mycontext } from "./MyContextProvider";
import "./styles.css";
export default function App() {
//This is the way of getting value from context here useContext is the builtin hook and Mycontext is the context name
const { setLibraries, setSoftwareComponents } = useContext(Mycontext);
//After getting data from API use setLibraries and setSoftwareComponents to store data in the state(context) instead of local storage.
return (
<div>
<ChildComponent />
</div>
);
}
Ребенок.js
import { useContext } from "react";
import { Mycontext } from "./MyContextProvider";
const ChildComponent = () => {
const { libraries, softwareComponents } = useContext(Mycontext);
//Here is your state you can use it as your need.
console.info(libraries, softwareComponents);
return <h1>Child Component</h1>;
};
export default ChildComponent;
Вы не должны использовать localStorage только для обмена состоянием. Вместо этого используйте Context с useState или useReducer. Вот статья о том, как это сделать, из документации по реакции: beta.reactjs.org/learn/scaling-up-with-reducer-and-context