1

I have the following app entry component:

  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();
  }, []);

I am fetching Arrays from two endpoints and then set the result in the Local Storage, so I can read from it in other components.

A child component is using the data like this:

  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>

Goal/Challenge:

I want to use React.Context to remove local storage implementation but I am not sure how to keep it as simple as possible.

I only saw guides which implemented dispatch actions and so on but this seems already too complex because I only fetch the data and don't change it as I only render it.

Are there any tipps or guides how to start with this?

1

2 Answers 2

1

Possible implementation with 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()
Sign up to request clarification or add additional context in comments.

Comments

1

Here is the complete setup for React Context. Please use typescript if needed.

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>
    
  );
}

Child.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.log(libraries, softwareComponents);
  
  return <h1>Child Component</h1>;
};
export default ChildComponent;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.