Stop Prop Drilling With React Context API

David Ang July 17, 2024

Do you have a similar code that you pass props around from parent to child components?



// src/App.js
import React from 'react';
import ProductImage from './components/ProductImage';
import ProductDescription from './components/ProductDescription';

const App = () => {
  const s3Settings = {
    bucketName: 'my-bucket',
    region: 'us-east-1',
  };

  const contentfulSettings = {
    spaceId: 'your-space-id',
    accessToken: 'your-access-token',
  };

  return (
    
<ProductImage s3Settings={s3Settings} /> <ProductDescription contentfulSettings={contentfulSettings} />
); }; export default App; end

 



// src/components/ProductImage.js
import React from 'react';
import Image from './Image';

const ProductImage = ({ s3Settings }) => {
  return (
    
<Image s3Settings={s3Settings} imagePath="example.jpg" />
); }; export default ProductImage; end

 



// src/components/Image.js
import React from 'react';

const Image = ({ s3Settings, imagePath }) => {
  return (
    <img
      src={`https://${s3Settings.bucketName}.s3.${s3Settings.region}.amazonaws.com/${s3Settings.basePath}${imagePath}`}
      alt="Product"
    />
  );
};

export default Image;

end

 



// src/components/ProductDescription.js
import React from 'react';
import DescriptionFetcher from './DescriptionFetcher';

const ProductDescription = ({ contentfulSettings }) => {
  return (
    
<DescriptionFetcher contentfulSettings={contentfulSettings} />
); }; export default ProductDescription; end

 

If you find yourself passing in props around from parent to child and you are tired of it, you might benefit from using React Context API, which s a built-in feature of React.

Using React Context API, this becomes a provider that wraps our App component tree and becomes available in every components within.

 

Let’s create the Context:



// src/context/S3Context.js
import React, { createContext } from 'react';

const S3Context = createContext();

export const S3Provider = ({ children, settings }) => (
  <S3Context.Provider value={settings}>{children}</S3Context.Provider>
);

export default S3Context;

end

 

Similar with when creating our Contentful Context:



// src/context/ContentfulContext.js
import React, { createContext } from 'react';

const ContentfulContext = createContext();

export const ContentfulProvider = ({ children, settings }) => (
  <ContentfulContext.Provider value={settings}>{children}</ContentfulContext.Provider>
);

export default ContentfulContext;


end

 

Let's now use them as providers to our App:




// src/App.js
import React from 'react';
import ProductImage from './components/ProductImage';
import ProductDescription from './components/ProductDescription';
import { S3Provider } from './context/S3Context';
import { ContentfulProvider } from './context/ContentfulContext';

const App = () => {
  const s3Settings = {
    bucketName: 'my-bucket',
    region: 'us-east-1',
    basePath: 'images/',
  };

  const contentfulSettings = {
    spaceId: 'your-space-id',
    accessToken: 'your-access-token',
  };

  return (
    <S3Provider settings={s3Settings}>
      <ContentfulProvider settings={contentfulSettings}>
        
</ContentfulProvider> </S3Provider> ); }; export default App; end

 




// src/components/ProductImage.js
import React from 'react';
import Image from './Image';

const ProductImage = () => {
  return (
    
); }; export default ProductImage; end

 

Notice that we don't pass the prop settings anymore, but we just retrieve them from the Context directly:



// src/components/Image.js
import React, { useContext } from 'react';
import S3Context from '../context/S3Context';

const Image = ({ imagePath }) => {
  const s3Settings = useContext(S3Context);

  return (
    <img
      src={`https://${s3Settings.bucketName}.s3.${s3Settings.region}.amazonaws.com/${s3Settings.basePath}${imagePath}`}
      alt="Product"
    />
  );
};

export default Image;

end

 

And we do similarly with retrieving the Contentful settings for the ProductDescription



// src/components/ProductDescription.js
import React, { useContext } from 'react';
import DescriptionFetcher from './DescriptionFetcher';
import ContentfulContext from '../context/ContentfulContext';

const ProductDescription = () => {
  const contentfulSettings = useContext(ContentfulContext);

  return (
    
<DescriptionFetcher contentfulSettings={contentfulSettings} />
); }; export default ProductDescription; end

 

This makes for a more cleaner code and you only retrieve the necessary settings where you need them.

If you need help migrating to React or refactoring your code into a cleaner, more maintainable approach, don't hesitate to contact us.