Writing cleaner React code for better maintainability and testability

Mr Super Shetty
A Web Developer
Published in
4 min readOct 9, 2023

Writing maintainable code should be the number one goal while developing. What do we mean by maintainable code

  1. Testable and properly Tested via UTs
  2. Readable by anyone
  3. Easy to change

Let’s look at the below code and make it more maintainable

interface IGetStrengthPercentageProps {
network: string;
ip: string;
condition: number;
}

interface INetworkDetailsProps {
networkType?: string,
ipAddress?: string,
condition?: number,
}

const NetworkDetails = (props?: INetworkDetailsProps) => {
const percentProps = {
network : props?.networkType || "unknown",
ip : props?.ipAddress || "unknown",
condition: props?.condition || 0,
};

const percentage = getStrengthPercentage(percentProps);

return props ? (
<>
Network: {percentage && `strength ${percentage} %`} {props.networkType} {props.ipAddress}
</>
) : (<>'No Network data'</>) ;
}

😱 wait this can be better. You are joking right

Before we begin. Name of several functions can be better so suggest in comment ;)

First, remove the ternary operator

const NetworkDetails = (props?: INetworkDetailsProps) => {

if (!props) {
return (<>'No Network data'</>);
}

......

return (
<>
Network: {percentage && `strength ${percentage} %`} {props.networkType} {props.ipAddress}
</>
);
}

Early exit makes the code more readable. It also ensures code doesn’t break if the object is undefined. We can also remove the ? (optional chaining operator), if we want, in subsequent code now that the props is always defined.

Move the transformation to a function

function fillMissingProps(props: INetworkDetailsProps) {
const percentProps = {
network : props.networkType || "unknown",
ip : props.ipAddress || "unknown",
condition: props.condition || 0,
};
return percentProps;
}

const NetworkDetails = (props?: INetworkDetailsProps) => {
....
const percentProps = fillMissingProps(props);
const percentage = getStrengthPercentage(percentProps);
....
}

Now the code is more readable. The function is also smaller. Again we have removed the optional chaining as the object can never be undefined.

Clean up the JSX.

interface IPercentageTextProps { 
percentage: number
}

const PercentageText = ({percentage}: IPercentageTextProps) => {
if (percentage === undefined) {
return <></>;
}
return (
<>strength {percentage} %</>
);
}

const NetworkDetails = (props?: INetworkDetailsProps) => {
.....

return (
<>
Network:
<PercentageText percentage={percentage} />
{" "}{props.networkType}
{" "}{props.ipAddress}
</>
);
}

By splitting the percentage logic we are not only making it more testable but also making the code cleaner to read. For numbers, && doesn’t work; as 0 equates to false hence the explicit undefined check.

We split each printed prop on new line for readability. But now we need to add an explicit space.

Fix the optional properties

interface INetworkDetailsProps {
networkType: string | undefined,
ipAddress: string | undefined,
condition: number | undefined,
}

The reason we marked these properties with ? is to let typescript know that it can be undefined. But by doing this typescript won’t throw an error if we skip any of these properties. So we remove the ? and replace it with union type and let typescript know that this can be undefined but its required.

Add return types

We are missing the return type everywhere. Let’s add a return type to every function.

type TNetworkDetails = (props?: INetworkDetailsProps) => JSX.Element;
const NetworkDetails: TNetworkDetails = (props) => {
....
}
type TPercentageText = (props: IPercentageTextProps) => JSX.Element;
const PercentageText: TPercentageText = ({percentage}) => {
....
}
function fillMissingProps(props: INetworkDetailsProps): IGetStrengthPercentageProps {
....
}

Add types for Objects

Adding types for objects is optional but it helps the editor with code completion

function fillMissingProps(props: INetworkDetailsProps): IGetStrengthPercentageProps {
const percentProps: IGetStrengthPercentageProps = {
....
};
return percentProps;
}

Give a displayName to our jsx function

This helps with snapshot tests else in the parent component when we do shallow( ) testing the name will be missing in the snapshot. (Newer versions on React/Jest might have fixed this)

const NetworkDetails = (props?: INetworkDetailsProps): JSX.Element | String => {
.....
}
NetworkDetails.displayName = "NetworkDetails"

Destructure some of the params

This is just to make the code more readable and explicit. Also now that the jsx is smaller we remove the spaces({ “ “}) and put all in one line

const NetworkDetails: TNetworkDetails = (props) => {
if (!props) {
return <>No Network data</>;
}

const { networkType, ipAddress, condition } = props;
const percentProps = fillMissingProps({ networkType, ipAddress, condition });
const percentage = getStrengthPercentage(percentProps);

return (
<>
Network:
<PercentageText percentage={percentage} /> {networkType} {ipAddress}
</>
);
};

Finally lets split code into logical blocks or files

function fillMissingProps(props: INetworkDetailsProps) {
const percentProps: IGetStrengthPercentageProps = {
network: props.networkType || "unknown",
ip: props.ipAddress || "unknown",
condition: props.condition || 0,
};
return percentProps;
}
interface IPercentageTextProps {
percentage: number;
}

type TPercentageText = (props: IPercentageTextProps) => JSX.Element;

const PercentageText: TPercentageText = ({ percentage }) => {
if (percentage === undefined) {
return <></>;
}
return <>strength ${percentage} %</>;
};
interface INetworkDetailsProps {
networkType: string | undefined;
ipAddress: string | undefined;
condition: number | undefined;
}

type TNetworkDetails = (props?: INetworkDetailsProps) => JSX.Element;

const NetworkDetails: TNetworkDetails = (props) => {
if (!props) {
return <>No Network data</>;
}

const { networkType, ipAddress, condition } = props;
const percentProps = fillMissingProps({ networkType, ipAddress, condition });
const percentage = getStrengthPercentage(percentProps);

return (
<>
Network:
<PercentageText percentage={percentage} /> {networkType} {ipAddress}
</>
);
};

Want us to write more

Hit claps if you liked it. It will encourage us to write more. Follow, for more posts. Comment below if you have any other suggestions or inputs.

--

--