Stop Prop Drilling With React Context API
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.