DEV Community

Cover image for How to create React Micro Frontend/Microservice (example) cloning NY Times sidebar widget
Muhammad Azfar Aslam
Muhammad Azfar Aslam

Posted on • Edited on

How to create React Micro Frontend/Microservice (example) cloning NY Times sidebar widget

Bonjour,
Today, I will try to demonstrate a concept of microservice in react js. We all know that Cloud Microservice Architecture is the favorite architecture of many developers these days. One of the popular examples in production with monthly traffic of 387.17M (Oct, 22) is "Netflix". My example is just a small widget, nothing compared to Netflix of course.

I am going to clone a sidebar widget of NY times.

Steps 1
For this just create a new react app using this command

npx create-react-app ny-times-microservice-widget-clone

Now, download some packages

npm i axios
npm i parcel

Then add the following code in the package.json file.

"build:widget": "parcel build src/index.js --no-source-maps --dist-dir widget",

Now let's start some coding :)

Steps 2

  • Create a folder components inside the src folder.
  • Create a new file inside named PostsWidget.jsx
  • Write the following lines of code.
const PostsWidget = () => {
  return (
    <section>
      <div>
        <h3>Tags</h3>
        <h3>This is a title</h3>
        <p>1 Reactions</p>
      </div>
    </section>
  );
};

export default PostsWidget;
Enter fullscreen mode Exit fullscreen mode

Here we just created a component that will render two headings and one paragraph at the front-end. Let's add some styling (Note: all styling is copied from NY Times).

  • Create a new file inside components folder named PostsWidget.module.css
.storyWrapper{
 border-bottom: 1px solid #dfdfdf;
 padding: 16px 0px
}

.subHeading{
    color: #727272;
    font-size: 0.6875rem;
    font-weight: 700;
    text-transform: uppercase;
    line-height: 1.35em !important;
    letter-spacing: 1px !important;
    margin-bottom: 0.25rem;
}

.mainHeadind{
    color: #121212;
    font-size: 1.375rem;
    line-height: 1.2em;
    letter-spacing: 0.01em;
    font-weight: 700;
    -webkit-font-smoothing: antialiased;
    margin: 0;
}

.reactions{
    color:  #727272;
    font-size: 0.625rem;
    line-height: 1.25em;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    margin: 0;
    margin-top: 0.25rem;
}
Enter fullscreen mode Exit fullscreen mode
import styles from "./PostsWidget.module.css";
...
<h3 className={styles.subHeading}>Tags</h3>
<h3 className={styles.mainHeadind}>This is a title</h3>
<p className={styles.reactions}>1 Reactions</p>
...
Enter fullscreen mode Exit fullscreen mode

Steps 3
API integration, I am using dummyjson.com for dummy data.

const [articles, setArticles] = useState([]);
...
useEffect(() => {
    axios
      .get(`https://dummyjson.com/posts?skip=0&limit=5`)
      .then(function (response) {
        console.log("response", response?.data);
        setArticles(response.data);
      })
      .catch(function (error) {
        setError("error");
      });
  }, [limit, skip]);
...
Enter fullscreen mode Exit fullscreen mode

Step 4
A div with data attributes to pass props and render this widget.
<div class="post-widget" data-skip="0" data-limit="5"></div>

Step 5
Targeting this div and passing props to our component. Go to src/index.js. Now, we'll use a JavaScript selector (querySelectorAll) to target the div. Then we will loop through it so we can render this widget as many times as we want on the same page.

...
import PostsWidget from './components/PostsWidget.jsx';

const widgets = document.querySelectorAll('.post-widget')

widgets.forEach(widget => {
    ReactDOM.render(
        <React.StrictMode>
            <PostsWidget widget={widget} />
        </React.StrictMode>,
        widget
    );
})
...
Enter fullscreen mode Exit fullscreen mode

Then, get this prop inside component and passing it to API endpoint.

...
const PostsWidget = ({ widget }) => {
  const skip = widget.getAttribute("data-skip") || 0;
  const limit = parseInt(widget.getAttribute("data-limit") ?? 5);
...
  const [error, setError] = useState(false);

  useEffect(() => {
    axios
      .get(`https://dummyjson.com/posts?skip=${skip}&limit=${limit}`)
      .then(function (response) {
        console.log("response", response?.data);
        setArticles(response.data);
      })
      .catch(function (error) {
        setError("error");
      });
  }, [limit, skip]);

  if (error) {
    return <div>{error}</div>;
  }
Enter fullscreen mode Exit fullscreen mode

now map all the articles

...
{articles?.posts?.map((article) => {
        return (
          <div className={styles.storyWrapper} key={article.id}>
            <h3 className={styles.subHeading}>{article?.tags?.toString()}</h3>
            <h3 className={styles.mainHeadind}>
            {article?.title}
            </h3>
            <p className={styles.reactions}>{article?.reactions} Reactions</p>
          </div>
        );
})}
...
Enter fullscreen mode Exit fullscreen mode

Step 6
Build, a normal react build will create multiple static files but we need a single file for JavaScript and CSS to target this widget. For this purpose, we install Parcel at the start. Let's create a build using this package.

yarn build:widget

Step 7
Host your widget somewhere. For learning purposes, I've served this build locally and used it inside an HTML file to show you guys.

...
<link rel="stylesheet" href="http://192.100.00.00:3000/index.css">
....
<body>
  <div class="post-widget" data-skip="0" data-limit="5"></div>
  <script src="http://192.100.00.00:3000/index.js"></script>
</body>
...
Enter fullscreen mode Exit fullscreen mode

You can find the complete code here. My vscode directory before the build.

Image description

My vscode directory after the build.

Image description

NY times widget for reference

Image description

This is how react widget will look.

Image description

What if we need only the JS link and HTML div, no CSS link
Yes, we can do it. just need to add another hook. Go to your PostWidget.js file and write following code

useEffect(() => {
    const fetchCSS = async () => {
      try {
        const response = await axios.get('http://192.100.00.00:3000/index.css');
        const style = document.createElement('style');
        style.textContent = response.data;
        document.head.appendChild(style);
      } catch (error) {
        console.error(error);
      }
    };
    fetchCSS();
  }, []);
Enter fullscreen mode Exit fullscreen mode

This hook will add your CSS code in the head direct. This is one way of doing it, not sure which one is better. Let me know your opinion in the comments.

If you find this standalone react app (microservice) helpful then please like ❤ and share it with your friends, follow me on LinkedIn for more helpful resources.


Other links:

Top comments (0)