When developing in React there’s one error I commonly see in the console while debugging and it’s always this one:
Warning: Each child in a list should have a unique “key” prop.
<insert meme about harry, hermoine and ron>
Thankfully this is a very simple problem to fix, as the warning implies you just need to make sure that each iteration of the <li> tag has it’s own unique key assigned to it. Take, for example, this code:
import * as React from "react";
interface IProps {
Status: string;
}
interface IError {
Status: "400" | "401" | "402" | "403" | "404" | "500";
Description: string;
Color: string;
}
const ReactExample: React.FC<IProps> = React.memo(( props ) => {
const [errors, setErrors] = React.useState<IError[]>([]);
React.useEffect(() => {
if (props.Status == "400") {
newErrors.push({
Status: "400",
Description: "Bad request",
Color: "yellow"
});
}
if (props.Status == "401") {
newErrors.push({
Status: "401",
Description: "Unauthorized",
Color: "yellow"
});
}
if (props.Status == "402") {
newErrors.push({
Status: "402",
Description: "Payment Required",
Color: "yellow"
});
}
if (props.Status == "403") {
newErrors.push({
Status: "403",
Description: "Forbidden",
Color: "red"
});
}
if (props.Status == "404") {
newErrors.push({
Status: "404",
Description: "Not found",
Color: "yellow"
});
}
if (props.Status == "500") {
newErrors.push({
Status: "500",
Description: "Internal server error",
Color: "red"
});
}
setErrors(newErrors);
}, []);
return (
<div className="http-status-errors">
{errors.length > 0 ? (
<ul>
{errors.map((error: IError) => (
<li className={"color-" + error.Color}>
<span>{error.Description}</span>
</li>
))}
</ul>
) : null}
</div>
);
});
export default ReactExample;
To fix the error for this example you will want to not only add a key to the <li> tag but you will also need something you can pull a unique value from. Your absolute best bet will always be to use a GUID, and if working with an API you will ideally have one returned with the dataset. However in this example you’ll notice IError does not contain a GUID that we can use, however the Status property will be unique, so one solution might look like:
return (
<div className="http-status-errors">
{errors.length > 0 ? (
<ul>
{errors.map((error: IError) => (
<li key={error.Status} className={"color-" + error.Color}>
<span>{error.Description}</span>
</li>
))}
</ul>
) : null}
</div>
)
Unfortunately you aren’t always so lucky as to get a unique identity back with your data, so what do you do in that case? Well, as a last resort we can simply add an iterator to our map call and use that:
import * as React from "react";
interface IProps {
Status: string;
}
interface IError {
Status: "400" | "401" | "402" | "403" | "404" | "500";
Description: string;
Color: string;
}
const ReactExample: React.FC<IProps> = React.memo(( props ) => {
const [errors, setErrors] = React.useState<IError[]>([]);
React.useEffect(() => {
if (props.Status == "400") {
newErrors.push({
Status: "400",
Description: "Bad request",
Color: "yellow"
});
}
if (props.Status == "401") {
newErrors.push({
Status: "401",
Description: "Unauthorized",
Color: "yellow"
});
}
if (props.Status == "402") {
newErrors.push({
Status: "402",
Description: "Payment Required",
Color: "yellow"
});
}
if (props.Status == "403") {
newErrors.push({
Status: "403",
Description: "Forbidden",
Color: "red"
});
}
if (props.Status == "404") {
newErrors.push({
Status: "404",
Description: "Not found",
Color: "yellow"
});
}
if (props.Status == "500") {
newErrors.push({
Status: "500",
Description: "Internal server error",
Color: "red"
});
}
setErrors(newErrors);
}, []);
return (
<div className="http-status-errors">
{errors.length > 0 ? (
<ul>
{errors.map((error: IError, i) => (
<li key={i} className={"color-" + error.Color}>
<span>{error.Description}</span>
</li>
))}
</ul>
) : null}
</div>
);
});
export default ReactExample;
Save and reload your app and you’ll find that your warning is gone.