The way you're replacing <br> is fine, other than you might want to allow for spaces before the closing >, and an optional / just before the > as well:
const fixed = note.body.replace(/<br\s*\\?>/g, "\r\n");
But that doesn't solve the problem that what you're getting is HTML, not plain text. You're best off getting the other end to send you the text rather than HTML. By sending you HTML, they're giving you a significant amount of work to do. You don't want to just replace <br> with line breaks, because HTML can have all sorts of other things in it, such as named character entities (<, &, etc.), numeric character entities (such as c;), script tags (opening the possibility of XSS attacks), etc. React is smart when you output text and escapes < and & and such to that they're output as those characters, not HTML, so if the HTML you receive has, say, < in it, you'll actually see &, l, t, and ; in the display, which isn't idea. If your starting point is HTML, interpreting it correctly without allowing scripts and such is difficult. (React does have an option for injecting raw HTML, but it's got an absurdly-awkward name for a reason. :-) )
Once you have the text, with standard line breaks (\r, \n, or \r\n), you can render each line in its own div to get line breaks in the output, since normally in HTML a line break (or any run of whitespace) is just a single space:
<p className="mb-1">{
fixed.split(/[\r\n]+/).map(line => <div>{line}</div>)
}</p>
Example:
const Example = ({fixed}) => {
return <p className="mb-1">{
fixed.split(/[\r\n]+/).map(line => <div>{line}</div>)
}</p>;
};
const str =
"This is a string with line breaks.\r\n" +
"Line 2\r\n" +
"Line 3";
ReactDOM.render(
<Example fixed={str} />,
document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.4.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.4.2/umd/react-dom.production.min.js"></script>