React.js & Blazor: A Component Comparison
For many, learning to code in a new environment is intimidating, but it doesn't have to be.
Whether you are a JavaScript developer who is used to slinging components in React.js, or a C#/.NET developer who prefers throwing components around in Blazor, my goal is to have you at least a little curious about the other side by the end of this.
To get the most out of this, I encourage you to check out the repo for my project on GitHub, but I will be including pictures for those who want to just read through this article without playing in their preferred IDE. So... let's get into it!
Starting with some prerequisites, this article will be assuming you know the basics of HTML and CSS (though we will not be focusing on those), and that you are familiar with either React.js or Blazor. If you don't have that foundation, you're still welcome to read this article, but you might find yourself missing certain aspects (though I will try to make this an overview anyone with any experience in development can follow along with).
Next let's briefly talk about what this is vs what this is not.
What this is:
What this is not:
For the purposes of this article, we won't be going into the folder structure of either environment, but it's enough to know that you'll find everything you need to follow along in the "Components" folder of the BlazorStepper project, and the "src" folder of the ReactStepper project. And when running either project you should see the following:
Parent Component:
For the purposes of consistency the stepper component in both projects was named "Stepper" (.tsx for React.js and .razor for Blazor) and both were put in the folders listed above for each project. The parent component however, is different for both.
For the ReactStepper project you will find the parent component of the stepper in the "src" folder labeled as "App.tsx"; commonly used as the home page for a React.js project.
For the BlazorStepper project, the parent component is in the "Pages" folder within the "Components" folder under the name "Home.razor"; the common name of the home page file in a Blazor project.
Let's take a look at both, starting with "App.tsx" (the React.js parent component):
Notice the top two lines; the "import" sections. In Blazor these would be "@using" instead of "import", but in both cases they do roughly the same thing; they connect your current file to other files within your project allowing them to use those other files. In the React.js project we are using these "import" lines to bring in "useState" (used to create a variable representing a given state and a function to change that state), and the "Stepper" component.
Next you'll see the parent component named as a function (in React.js this is a functional component), followed by lines 5-13 which creates the logic for progressing the step forward and backward.
Finally, within the "return" section, you'll see the structure that will form what is shown to the user on the screen. Note the way the parameters are passed to the "Stepper" component as well as the other parameters within the various elements (style, onClick, and disabled). We'll compare those when looking at the Blazor parent component in a moment.
Now let's look at the Blazor parent component, "Home.razor":
One of the things that might jump out right away is the absence of any "@using" statements in the first lines. This is because, for this instance, everything the component needs is already accessible to it. The "Home" parent component already has access to the "Stepper" component without explicitly importing it via a "@using" statement.
Instead of anything required in this instance to import/use another file, the first two lines of the Blazor project include "@page" and "@rendermode" to perform two specific tasks.
Blazor, unlike React.js, has native page routing built in so all that is needed to for page routing is "@page" followed by the name you wish the page to have in double quotes (with "/" being used for the home page).
The "@rendermode" is an interesting one. In React.js every page is looked at as interactive by default (meaning the user can interact with elements on the page causing a re-render). In contast, Blazor components are not interactive by default and you have to use "@rendermode InteractiveServer" to allow the user to be able to interact with the elements on the page.
There are other things that "@rendermode" can be set to other than "InteractiveServer", but for the purposes of this article just know that it is what is required to allow the user to interact with the buttons on the page, and in contrast to that you would have to take extra steps in a React.js component to prevent a re-render. These two concepts are important to understand when comparing a React.js and Blazor component as they do require a mental shift when going from one to the other.
Another thing you'll notice is the "PageTitle" element. In a Blazor component this element controls what is put in the window tab as... well, the page title!
Similar to page routing, React.js does not natively have a way to do this and doing both would require adding things to your project like React Router and React Helmet.
The next difference between the "Home.razor" and "App.tsx" files is that the structural code for what will be shown on the screen is in different places.
While the React.js component requires that code to be in a "return", Blazor has no such requirement. Also the code itself is in a different section of the file, with Blazor having it in the middle of the page while React.js has it at the bottom.
Similarly, you'll notice that the functional code for the buttons is in different locations within the two files.
The Blazor component has it's functional code at the bottom of the page, while React.js components have it in the middle. Though in both cases, it's important to note that the functional code is often removed to a separate file for separation of concerns in larger projects.
The last two things in the parent components I want to point out is how things are passed to the elements and components, and how the inline CSS is handled.
Recommended by LinkedIn
In Blazor world you'll notice the "@" symbol is used to pass things like variables, functions, and to indicate an "on click" (and various other) events on an element. But in React.js world, everything is passed by way of an object.
Inline CSS? Object. Variable? Object. Function? Object.
Basically React.js is Oprah and everyone is getting an object.
Stepper Component:
Now that we've had a chance to look at the parent components, let's looks at the "Stepper" components.
As a reminder, it is "Stepper.tsx" in the React.js file and "Stepper.razor" for the Blazor file. With the React.js file being located in the "src" folder, and the Blazor file being in the "Components" folder.
Starting again with React.js, let's look at the file:
You'll notice the use of "import" again on the first line of this component, in this case it is importing the CSS file associated with the component. We won't be going over the CSS files themselves, as they are the exact same between the React.js and Blazor components, just know that you have to "import" CSS files when using React.js
Next you'll see something different from the last React.js file; the "interface". This is technically TypeScript and not specifically React.js, but it is used for type setting the parameters the component will be expecting as props and the inclusion of TypeScript in React.js projects is pretty common these days.
Ok, let's take a brief moment to pause and reflect on this, because no React.js is not type specific on it's own. But calm down, I can feel all the C#/.NET devs out there getting twitchy and starting to sweat. It's ok, because including TypeScript in your React.js project solves that and brings everything back around to type specificity in coding. Everybody happy? Good.
Moving on, you'll notice that the parameters (referred to as props in this case) are specified in the initial creation of the component, followed by the type assignment.
Following that you'll see that I had to turn the amount of steps ("stepsInStepper") into an array where each item in the array is the number of a step in order. This is done because React.js really likes making people map through arrays when it comes to looping through things in the "return" section of the component. React.js likes "map" almost as much as it likes "objects"... almost.
I want to point out that there are other ways for me to have accomplished the same thing without creating the "steps" array and mapping through it in the return, but I wanted to do it this way to show a similar approach with the Blazor component which you'll see momentarily.
The next thing worth pointing out in the React.js stepper component is the if/else statements.
It's important to note that you can not put an if/else statement directly into the return of a React.js component, and this typically requires the use of a ternary operator instead, but because I nested the if/else statement inside of the the map that is inside of a ternary operator, I am able to include it for improved readability instead of using multiple nested ternary operators.
The final two things I want to point out before moving on to the Blazor stepper is the CSS class names and the "export" line within the React.js component.
You'll notice that CSS class names are assigned with "className" rather than the typical "class" label. This is something minor, and most people quickly get used to it, but it can trip you up when you first start coding in React.js
And finally, it's important to note that you have to "export" your React.js component in order for other components in the project to be able to find it. This can be done as shown at the bottom of the file, or can be included by adding "export" before "function" in the creation of the component.
Now let's look at the Blazor "Stepper.razor" component:
One thing I didn't mention before that you've probably noticed in both Blazor files is the absence of any type of defining the component. By default Blazor understands that a "ComponentName.razor" file is a component by the name of the file.
Another thing that you'll notice for this file is there is no importing or bringing in of the CSS file. This is because Blazor follows a convention where you can name the CSS file the same as the component and it will automatically connect the two.
So, in this case, the component's name is "Stepper.razor" and the CSS file is "Stepper.razor.css", which lets Blazor know that the CSS file belongs to the component.
In regards to the handling of CSS and not defining a component beyond making it a ".razor" file, Blazor is cleaner and easier to read than React.js. But I also have to say it comes with the caveat of Blazor also being more bloated and heavy of a program than something similar created with React.js. Feel free to look into those more on your own as it is more in-depth than this article is intended to be.
In the Blazor stepper component, you'll also notice that the "@for" and "@if/else" statements are easily placed right into the structural code without having to jump through any additional hoops. This adds to the readability of the file and does result in less lines of code compared to the React.js equivalent.
Lastly, you'll notice that the parameters for the Blazor component are defined in the "@code" section at the bottom of the file rather than more in the middle where React.js has it.
Conclusion:
While this article is not intended to be an exhaustive review of React.js and Blazor components, I'm hoping it has given you enough insight to get you comfortable with trying whichever you are least familiar with.
There are some differences between the two, but I feel the similarities are enough to lay the ground work for an ease of sorts in transitioning from one to the other.
Who knows, maybe if you're an avid React.js developer you might find yourself switching sides after experimenting with Blazor? Or, if you are a Blazor dev, you might be tempted by the lightweight appeal of React.js in comparison to Blazor.
If you do give the other side a try, let me know in the comments. And for those who have already used both, let me know which you prefer and why.
And remember, trying out the one you are least familiar with can be a great way to start learning a new coding language if you only know C# or JavaScript to start with.
Now go build something, never stop learning, and never stop being curious.
I always find these kind of comparisons fascinating, I don't know much about blazor and learned a bit! thanks!
Excellent comparison. This feels a lot more approachable than Angular tbh. I feel like I could probably build a janky component pretty easily with my limited C# knowledge.
started on react, now im a blazor developer!