DEV Community

Cover image for Improve your React skills with these 5 tips
Johnny Boy
Johnny Boy

Posted on

Improve your React skills with these 5 tips

Summary

We will go through a piece of Javascript code that we have all seen(or eventually will see) in some of our careers. And I will try to make some improvements and I will provide some arguments on why I make them. I hope you find this helpful!

The scene of the crime

function Othercomponent({ children, props }) {
  return <div {...props}>{children}</div>;
}
const MyComponent = ({
  id,
  text,
  style,
  extraProps,
  oneList,
  containerOfThings,
  aType,
}) => {
  const whichString = aType == "SomeString" ? "aString" : "bString";
  const whichNumber = aType == "SomeString" ? 123 : 321;
  const extraThing = "Hey! I am a string";
  if (containerOfThings && oneList && oneList.length > 1) {
    return (
      <ul>
        <Othercomponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[0]}
          extraThing={extraThing}
        >
          {text}
        </Othercomponent>
        <Othercomponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[1]}
          extraThing={extraThing}
        >
          {text}
        </Othercomponent>
        <Othercomponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[2]}
          extraThing={extraThing}
        >
          {text}
        </Othercomponent>
      </ul>
    );
  } else {
    return (
      <Othercomponent
        whichString={whichString}
        whichNumber={whichNumber}
        id={id}
        style={style}
        extraProps={extraProps}
        extraThing={extraThing}
        alt={text}
      >
        {text}
      </Othercomponent>
    );
  }
  return <></>;
};

const MyApp = (props) => (
  <MyComponent id={123} aType={"SomeString"} text="some content" {...props} />
);

Ok... bear with me now. I know it is ugly. Let us try to make it better one step at the time.

#1 Stay consistent

In the first component(<Othercomponent/>) we are declaring our component in the way: function XXXXX() { /* ... */ } and not in a PascalCase. While in the second component(<MyComponent/>) we are using arrow functions and PascalCase. It is important to stay consistent across your codebase so when you start to create another component you don't have to question yourself or your teammates on what is the right way to define my components. If you have a consistent codebase it allows your fellow developers to make better assumptions on what's the current state and rules followed, liberating from questioning every single step of the way while implementing code around an existing piece of code.

From:

function Othercomponent({ children, props }) {
  return <div {...props}>{children}</div>;
}

To:

const OtherComponent = ({ children, props }) => {
  return <div {...props}>{children}</div>;
};

Result:

const OtherComponent = ({ children, props }) => {
  return <div {...props}>{children}</div>;
};

const MyComponent = ({
  id,
  text,
  style,
  extraProps,
  oneList,
  containerOfThings,
  aType,
}) => {
  const whichString = aType == "SomeString" ? "aString" : "bString";
  const whichNumber = aType == "SomeString" ? 123 : 321;
  const extraThing = "Hey! I am a string";
  if (containerOfThings && oneList && oneList.length > 1) {
    return (
      <ul>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[0]}
          extraThing={extraThing}
        >
          {text}
        </OtherComponent>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[1]}
          extraThing={extraThing}
        >
          {text}
        </OtherComponent>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[2]}
          extraThing={extraThing}
        >
          {text}
        </OtherComponent>
      </ul>
    );
  } else {
    return (
      <OtherComponent
        whichString={whichString}
        whichNumber={whichNumber}
        id={id}
        style={style}
        extraProps={extraProps}
        extraThing={extraThing}
        alt={text}
      >
        {text}
      </OtherComponent>
    );
  }
  return <></>;
};

const MyApp = (props) => (
  <MyComponent id={123} aType={"SomeString"} text="some content" {...props} />
);

#2 Leverage the language/framework features

One incredibly common thing I've seen recently when doing code reviews for Frontend Engineers is that we are no longer familiar with the features that the framework or the syntactic sugar the language offers.

Children as props

We know that everything you write inside a React component is a children and children are passed as props(you can send them inside or with the children={'my child'} prop). So we can always leverage this when we are implementing our components.

No return statement

We can make use of the JS feature of the one-liner functions, that don't need any return keyword. Please use the features that the good people working on them! https://github.com/tc39/proposals

From:

const OtherComponent = (props) => {
  return <div {...props} />;
};


const MyComponent = ({
  id,
  text,
  style,
  extraProps,
  oneList,
  containerOfThings,
  aType,
}) => {
  // ..
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[0]}
          extraThing={extraThing}
        >
          {text}
        </OtherComponent>
  // ...

To:

const OtherComponent = (props) => <div {...props} />;

const MyComponent = ({
  id,
  children,
  style,
  extraProps,
  oneList,
  containerOfThings,
  aType,
}) => {
  // ...
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[0]}
          extraThing={extraThing}
        >
          {children}
        </OtherComponent>
  // ...

Result:

const OtherComponent = (props) => <div {...props} />;

const MyComponent = ({
  id,
  children,
  style,
  extraProps,
  oneList,
  containerOfThings,
  aType,
}) => {
  const whichString = aType == "SomeString" ? "aString" : "bString";
  const whichNumber = aType == "SomeString" ? 123 : 321;
  const extraThing = "Hey! I am a string";
  if (containerOfThings && oneList && oneList.length > 1) {
    return (
      <ul>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[0]}
          extraThing={extraThing}
        >
          {children}
        </OtherComponent>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[1]}
          extraThing={extraThing}
        >
          {children}
        </OtherComponent>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          id={id}
          style={style}
          extraProps={extraProps}
          alt={oneList[2]}
          extraThing={extraThing}
        >
          {children}
        </OtherComponent>
      </ul>
    );
  } else {
    return (
      <OtherComponent
        whichString={whichString}
        whichNumber={whichNumber}
        id={id}
        style={style}
        extraProps={extraProps}
        extraThing={extraThing}
        alt={children}
      >
        {children}
      </OtherComponent>
    );
  }
  return <></>;
};

const MyApp = (props) => (
  <MyComponent id={123} aType={"SomeString"} {...props}>
    some content
  </MyComponent>
);

#3 Being explicit without reason

Some people like to argue that we should always be explicit. That every single component should have all the props deconstructed. I understand that this approach is desirable in some scenarios, but in most cases is just noise to the code. If you have this need, please consider moving to Typescript(or if you just want to make better JS code in general). In our example we can make a lot of things implicit because we are deconstructing some variables that we never touch and we don't care.

From:

// ...
const MyComponent = ({
  id,
  children,
  style,
  extraProps,
  oneList,
  containerOfThings,
  aType,
}) => {
  // ...
  <OtherComponent
    whichString={whichString}
    whichNumber={whichNumber}
    id={id}
    style={style}
    extraProps={extraProps}
    alt={oneList[0]}
    extraThing={extraThing}
  >
    {children}
  </OtherComponent>

To:

// ...
const MyComponent = ({ oneList, containerOfThings, aType, ...props }) => {
  // ...
  <OtherComponent
    whichString={whichString}
    whichNumber={whichNumber}
    alt={oneList[0]}
    extraThing={extraThing}
    {...props}
  />

Result:

const OtherComponent = (props) => <div {...props} />;

const MyComponent = ({ oneList, containerOfThings, aType, ...props }) => {
  const whichString = aType == "SomeString" ? "aString" : "bString";
  const whichNumber = aType == "SomeString" ? 123 : 321;
  const extraThing = "Hey! I am a string";
  if (containerOfThings && oneList && oneList.length > 1) {
    return (
      <ul>
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          alt={oneList[0]}
          extraThing={extraThing}
          {...props}
        />
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          alt={oneList[1]}
          extraThing={extraThing}
          {...props}
        />
        <OtherComponent
          whichString={whichString}
          whichNumber={whichNumber}
          alt={oneList[2]}
          extraThing={extraThing}
          {...props}
        />
      </ul>
    );
  } else {
    return (
      <OtherComponent
        whichString={whichString}
        whichNumber={whichNumber}
        alt={oneList[0]}
        extraThing={extraThing}
        {...props}
      />
    );
  }
  return <></>;
};

const MyApp = (props) => (
  <MyComponent
    id={123}
    aType={"SomeString"}
    {...props}
    containerOfThings={true}
    oneList={["alt1", "alt2", "alt3"]}
  >
    some content
  </MyComponent>
);

#4 Reduce Logical branches / Make your code less error prone

We all love ternaries and unnecessary variables, I get it. I've fallen into this trap, where you want to make something work and then you decide that checking with an if or assigning a value with a ternary is the solution. Most of the time is not. It just increase the time you will spend on reaching full/good test coverage of your code.

When we add those logical branches once in a while we make dumb mistakes such a code that is unreachable or we make our code more complex than it should.

Remove the ternary if

One nifty trick that you should use to reduce logical branches from ternary ifs is the usage of maps(you can also call them hashes/objects). You can think of them as some configuration helpers. πŸ˜‡

From:

// ...
const whichString = aType == "SomeString" ? "aString" : "bString";
const whichNumber = aType == "SomeString" ? 123 : 321;
// ...
<OtherComponent
  whichString={whichString}
  whichNumber={whichNumber}
  alt={oneList[0]}
  extraThing={extraThing}
  {...props}
/>;
// ...

To:

// ...
const valuesMap = {
  SomeString: { str: "aString", num: 123 },
  OtherString: { str: "bString", num: 321 },
};
// ...
<OtherComponent
  whichString={valuesMap[aType].str}
  whichNumber={valuesMap[aType].num}
  alt={oneList[0]}
  extraThing={extraThing}
  {...props}
/>;
// ...

Result:

const OtherComponent = (props) => <div {...props} />;

const MyComponent = ({ oneList, containerOfThings, aType, ...props }) => {
  const valuesMap = {
    SomeString: { str: "aString", num: 123 },
    OtherString: { str: "bString", num: 321 },
  };
  const extraThing = "Hey! I am a string";
  if (containerOfThings && oneList && oneList.length > 1) {
    return (
      <ul>
        <OtherComponent
          whichString={valuesMap[aType].str}
          whichNumber={valuesMap[aType].num}
          alt={oneList[0]}
          extraThing={extraThing}
          {...props}
        />
        <OtherComponent
          whichString={valuesMap[aType].str}
          whichNumber={valuesMap[aType].num}
          alt={oneList[1]}
          extraThing={extraThing}
          {...props}
        />
        <OtherComponent
          whichString={valuesMap[aType].str}
          whichNumber={valuesMap[aType].num}
          alt={oneList[2]}
          extraThing={extraThing}
          {...props}
        />
      </ul>
    );
  } else {
    return (
      <OtherComponent
        whichString={valuesMap[aType].str}
        whichNumber={valuesMap[aType].num}
        alt={oneList[0]}
        extraThing={extraThing}
        {...props}
      />
    );
  }
  return <></>;
};

const MyApp = (props) => (
  <MyComponent
    id={123}
    aType={"SomeString"}
    {...props}
    containerOfThings={true}
    oneList={["alt1", "alt2", "alt3"]}
  >
    some content
  </MyComponent>
);

Remove complexity, remove the conditionals

It has been some years now that the Functional Programming(FP) paradigm has been around and re-hyped. So the time has come for you to stop using ifs and improve the quality of your code.

In this example we can see that there is unnecessary return, and the example is pretty dumb or obvious but I guarantee you will read or have read some code with conditions that are useless.

Now if we can work around having the same html structure for all the scenarios, it will make your code ridiculously simple. You might need to improve your CSS skills if you don't see a clear way on doing this.

Result:

const OtherComponent = (props) => <div {...props} />;

const MyComponent = ({ oneList = [], aType, ...props }) => {
  const valuesMap = {
    SomeString: { str: "aString", num: 123 },
    OtherString: { str: "bString", num: 321 },
  };
  const extraThing = "Hey! I am a string";
  return (
    <ul>
      {oneList.map((item) => (
        <OtherComponent
          whichString={valuesMap[aType].str}
          whichNumber={valuesMap[aType].num}
          alt={item}
          key={item}
          extraThing={extraThing}
          {...props}
        />
      ))}
    </ul>
  );
};

const MyApp = (props) => (
  <MyComponent
    id={123}
    aType={"SomeString"}
    {...props}
    containerOfThings={true}
    oneList={["alt1", "alt2", "alt3"]}
  >
    some content
  </MyComponent>
);

#5 Constants in your React Apps

My last advice for this article is this: Check your Constants!

Always make sure to leave them outside your React Components, you don't need to redeclare them every time the component is called. Also use set default values for your props, you will save some time by letting everyone know which is the default behavior of your component.

Result:

const STRING_TYPES = { SomeString: "SomeString", OtherString: "OtherString" };

const valuesMap = {
  SomeString: { whichString: "aString", whichNumber: 123 },
  OtherString: { whichString: "bString", whichNumber: 321 },
};

const extraThing = "Hey! I am a string";

const OtherComponent = (props) => <div {...props} />;

const MyComponent = ({
  aType = STRING_TYPES.SomeString,
  oneList = [],
  ...props
}) => (
  <ul>
    {oneList.map((item) => (
      <OtherComponent
        alt={item}
        key={item}
        extraThing={extraThing}
        {...valuesMap[aType]}
        {...props}
      />
    ))}
  </ul>
);

const MyApp = (props) => (
  <MyComponent
    id={123}
    aType={STRING_TYPES.SomeString}
    containerOfThings={true}
    oneList={["alt1", "alt2", "alt3"]}
    {...props}
  >
    some content
  </MyComponent>
);

The end!

I hope this helps you guys!

Cheers, stay safe!

Top comments (7)

Collapse
 
shofol profile image
Anower Jahan Shofol

Hi, Johnny, The article is nice. But in every improvement you've added full code of the snippet so it's bit hard for me to find the changes at a glance you've made.
It would be better if you could just show the changed portions in the specific improvement part. And, at last you can show all of the snippet.
Thanks for the article :)

Collapse
 
grekz profile image
Johnny Boy

Hi Anower!
Thanks for your comment, I've added the changes to each tip. With From: and To: sections.
Let me know if this helps.
Cheers!

Collapse
 
shofol profile image
Anower Jahan Shofol

Thanks for the extra work, Johnny. :) It's more understandable now.

Collapse
 
renso3x profile image
Renso3x

Nice article

Collapse
 
grekz profile image
Johnny Boy

Thanks Renso! πŸ™

Collapse
 
yougotwill profile image
Will G

Nice article! I learnt some new tricks. Thank you

Collapse
 
grekz profile image
Johnny Boy

I'm glad that it helped you! πŸ™