Creating React “Widgets” that can be embedded on any website, by anyone

npx create-react-app reddit-widget
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
);
<div id="root"></div>
const WidgetDivs = document.querySelectorAll('.reddit_widget')

// Inject our React App into each
WidgetDivs.forEach(Div => {
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
Div
);
}
<div class="reddit_widget"></div>
<div class="reddit_widget"></div>
  1. We can use Div.getAttribute(“data-subreddit”) to get our attribute from each DOM element. We can pass this a subreddit prop to our React component.
  1. We can pass the entire DOM element as a prop, to our React component. Allowing us to access the entire DOM element for each App. From there, we can do anything with the dom element. Including getting the attributes. For more information, check out using data attributes.
// index.js 

WidgetDivs.forEach(Div => {
ReactDOM.render(
<React.StrictMode>
<App domElement={Div} />
</React.StrictMode>,
Div
);
})
// src/App.js 

function App({ domElement }) {
const subreddit = domElement.getAttribute("data-subreddit")

return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
My favorite subreddit is /r/{subreddit}
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
import React, { useEffect, useState } from 'react';
import './App.css';

// Render each post
function renderPost(post){
const { data: { title, url, author, id } } = post
const authorUrl = `https://www.reddit.com/u/${author}`

return (
<div className="reddit_widget__post" key={id}>
<div className="reddit_widget__posted_by">
posted by <a href={authorUrl} className="reddit_widget__posted_by" target="_blank" rel="noopener noreferrer">u/{author}</a>
</div>
<a href={url} className="reddit_widget__title" target="_blank" rel="noopener noreferrer">{title}</a>
</div>
)
}

// Filter, since reddit always returns stickied posts up top
function nonStickiedOnly(post){
return !post.data.stickied
}

function App({ domElement }) {
const subreddit = domElement.getAttribute("data-subreddit")
const [loading, setLoading] = useState();
const [error, setError] = useState('');
const [data, setData] = useState([]);

useEffect(() => {
// Fetch data from reddit
setLoading(true)
fetch(`https://www.reddit.com/r/${subreddit}.json`)
.then((response) => response.json())
.then((data) => {
setLoading(false);
setData(data.data.children.slice(0, 10));
})
.catch((e) => {
console.log(e)
setLoading(false);
setError('error fetching from reddit');
});
}, [ subreddit ])

return (
<div className="reddit_widget__app">
<h1 className="reddit_widget__header">
Latest posts in <a href={`https://reddit.com/r/${subreddit}`} rel="noopener noreferrer">/r/{subreddit}</a>
</h1>
<div className="reddit_widget__inner">
{loading && "Loading..."}
{error && error}
{!!data.length && data.filter(nonStickiedOnly).map(renderPost)}
</div>
<p className="reddit_widget__powered_by">
This widget is powered by{" "}
<a
href="https://javascriptpros.com"
rel="noopener noreferrer"
target="_blank"
>
JavaScriptPros.com
</a>
</p>
</div>
);
}

export default App;
yarn add --dev parcel-bundler
"build:widget": "parcel build src/index.js --no-source-maps -d docs",
# .gitignore

# parcel
.cache

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store