Junaid Razaq
Junaid Razaq

Reputation: 251

How to simplify this code and complete four similar tasks four times?

So I am completing this task where I convert raw html in to a react component, and I need to complete this task 4 times, for 4 menu's in the Navigation Bar. The code works, however the code looks ugly and I am sure there is a way to complete the tasks with less lines. The code which is repeated which I would like to be more efficient is the processinginstructions and processinginstructionsTwo. The code is here:

import React, { useState, useEffect } from "react";
import { Grid, Container } from "@material-ui/core";
import { navSubMenuStyles } from "./Styles";
import "./stylesheets/NavBar.css";
import NavBar from "./NavBar";
import NavMenuLink from "./stylesheets/NavMenuLink";

function NavBarContent() {
  const pageName = ["HIDDEN-FOR-PRIVACY", "HIDDEN-FOR-PRIVACY"];
  const [content, setContent] = useState();
  const [contenttwo, setContenttwo] = useState();

  async function fetchData() {
    const res = await fetch("HIDDEN-FOR-PRIVACY" + pageName);
    res
      .json()
      .then((res) => {
        setContent(res[0].content.rendered.replace(/(\r\n|\n|\r)/gm, ""));
        setContenttwo(res[1].content.rendered.replace(/(\r\n|\n|\r)/gm, ""));
      })
      .catch((err) => console.log(err));
  }

  useEffect(() => {
    fetchData();
  }, []);

  var HtmlToReact = require("html-to-react");
  var HtmlToReactParser = require("html-to-react").Parser;

  var htmlInput = content;
  var htmlInputTwo = contenttwo;

  // Order matters. Instructions are processed in the order they're defined
  var processNodeDefinitions = new HtmlToReact.ProcessNodeDefinitions(React);
  var processingInstructions = [
    {
      //// subMenus \\// subMenus \\\\
      replaceChildren: true,
      shouldProcessNode: function (node) {
        return node.attribs && node.attribs["data-cat"] === "submenu";
      },
      processNode: function (node, children) {
        return (
          <li className="menu-link">
            {pageName[0]}
            <NavBar children={children} />
          </li>
        );
      },
    },
    {
      // replaceChildren:true,
      shouldProcessNode: function (node) {
        return node.parent && node.parent.name && node.parent.name === "h1";
      },
      processNode: function (node, children) {
        return null;
      },
    },
    {
      // Anything else
      shouldProcessNode: function (node) {
        return true;
      },
      processNode: processNodeDefinitions.processDefaultNode,
    },
  ];

  var processingInstructionsTwo = [
    {
      //// subMenus \\// subMenus \\\\
      replaceChildren: true,
      shouldProcessNode: function (node) {
        return node.attribs && node.attribs["data-cat"] === "submenu";
      },
      processNode: function (node, children) {
        return (
          <li className="menu-link">
            {pageName[1]}
            <NavBar children={children} />
          </li>
        );
      },
    },
    {
      // replaceChildren:true,
      shouldProcessNode: function (node) {
        return node.parent && node.parent.name && node.parent.name === "h1";
      },
      processNode: function (node, children) {
        return null;
      },
    },
    {
      // Anything else
      shouldProcessNode: function (node) {
        return true;
      },
      processNode: processNodeDefinitions.processDefaultNode,
    },
  ];
  var htmlToReactParser = new HtmlToReactParser();
  var reactComponent = htmlToReactParser.parseWithInstructions(
    htmlInput,
    () => true,
    processingInstructions
  );
  var reactComponenttwo = htmlToReactParser.parseWithInstructions(
    htmlInputTwo,
    () => true,
    processingInstructionsTwo
  );

  return (
    <div style={{ backgroundColor: "silver" }}>
      <Container
        style={{
          maxWidth: "1060px",
          width: "100%",
          height: "auto",
          display: "block",
        }}
      >
        <Grid container alignItems="center" style={{ display: "flex" }}>
          <Grid item xs={5}>
            Logo
          </Grid>
          <Grid item xs={7}>
            <nav>
              <ul style={{ display: "flex" }}>
                {reactComponent}
                {reactComponenttwo}
              </ul>
            </nav>
          </Grid>
        </Grid>
      </Container>
    </div>
  );
}

export default NavBarContent;

Any help would be much appreciated.

Upvotes: 0

Views: 52

Answers (1)

Luis
Luis

Reputation: 874

Will suggest you to start creating a Builder for the processing instructions. This will give you control over the order and properties you setup, but also to scale the builders to a library that allow you to encapsulate some boilerplate code in the future.

The code below is not intended as a complete solution, but as a sample of what could be done to address the problem of organizing and somewhat guarantee the order of instructions definitions.

Something along the lines of:

/*
* Setup the processing instructions builder
*/
function processingInstructionsBuilder() {
   var _instructions = [];
}

processingInstructionsBuilder.prototype.end = function() {
   return [...instructions];
};

processingInstructionsBuilder.prototype.newInstructions = function() {
   var builder = new instructionsBuilder(this, (props) => {
      this._instructions.push(props);
   });
   return builder;
};
// other builder functions here...

/*
* Setup the instructions builder
*/
function instructionsBuilder(parent, endCallback) {
   var _parent = parent || null;
   var _endCallback = endCallback || null;
   var _properties = {};
}

instructionsBuilder.prototype.end = function() {
   if (!!_endCallback) {
     _endCallback(_properties);
   }
   return this._parent || this._properties;
};

instructionsBuilder.prototype.canReplaceChildren = function(trueOrFalse) {
   // Some validations here...
   this._properties.replaceChildren = trueOrFalse;
   return this;
};

instructionsBuilder.prototype.shouldProcessNode = function(shouldProcessNodeFunc) {
   // Some validations here...
   this._properties.shouldProcessNode = shouldProcessNodeFunc;
   return this;
};

instructionsBuilder.prototype.processNode = function(processNodeFunc) {
   // Some validations here...
   this._properties.processNode = processNodeFunc;
   return this;
};
// other builder functions here...

Some sample usage...

/*
* Usage...
*/
var builder = new processingInstructionsBuilder();
// Gets an array with processing instructions, in the created order...
var instructions = builder
   .newInstructions(/* instructions 1 */)
      .canReplaceChildren(true)
      .shouldProcessNode(function(node) {
         // some useful code here... 
      })
      .processNode(function (node, children) {
         // some useful code here... 
      })
   .end(/* instructions 1 */)
   .newInstructions(/* instructions 2 */)
      .canReplaceChildren(false)
      .shouldProcessNode(function(node) {
         // some useful code here... 
      })
      .processNode(function (node, children) {
         // some useful code here... 
      })
   .end(/* instructions 2 */)
.end(/* processing instructions builder */);

/*
* Alternative usage...
*/
var builder1 = new instructionsBuilder();
var inst1 = builder1.canReplaceChildren(true)
.shouldProcessNode(function(node) {
   // some useful code here... 
})
.processNode(function (node, children) {
   // some useful code here... 
})
.end(/* instructions 1 */);

var builder2 = new instructionsBuilder();
var inst1 = builder2
.canReplaceChildren(false)
.shouldProcessNode(function(node) {
   // some useful code here... 
})
.processNode(function (node, children) {
   // some useful code here... 
})
.end(/* instructions 2 */);

Upvotes: 0

Related Questions