You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<p>In a mechanical machine, there are many cogs. Each cog collaborates with the others to function as a machine. To build a system capable of accomplishing an interesting task, multiple components are needed. These components often need to work in coordination together and, thus, must be able to communicate with each other. Data must flow between them. There are multiple ways to share data between components and we will go through all possible ways to share data between components. With each method, you will not only learn how but also when to choose that method. Note that advanced techniques for each approach will be covered in later tutorials. In this tutorial, we will cover:</p>
3
+
<ul>
4
+
<li>Basic component tree structure.</li>
5
+
<li>Communication between parent and child.</li>
6
+
<li>Communication between components at the same level.</li>
7
+
<li>Single source of truth.</li>
8
+
</ul>
9
+
<hrclass="my-4" />
10
+
<h1>Basic Component Tree Structure</h1>
11
+
<p>In Blazor, the simplest component hierarchy is a 3-level structure, as shown in the image below:</p>
<p>This foundational setup consists of an outer-most component (Level 0), a middle component (Level 1), and an inner-most component (Level 2). More complex hierarchies are merely extensions of this model, and the same communication techniques can be applied. Data typically flows from the root (Level 0) down to the deepest level (Level 2). For clarity, this tutorial uses a colour-coded approach: Level 0 is blue, Level 1 is green, and Level 2 is red.</p>
<p>In Blazor, the parent-child relationship is a fundamental aspect of component interaction, limited to 2 adjacent levels: a parent (Level 0) and its direct child (Level 1). Data can flow in 2 directions - parent to child or child to parent. This tutorial focuses solely on the parent to child flow, we will introduce more information in the next tutorials.</p>
18
+
<p>Consider the following child component, <strong>SimpleChild.razor</strong>:</p>
19
+
<prelanguage="razor"><div>
20
+
<h3>SimpleChild (Level 1)</h3>
21
+
<div>@Parameter1</div>
22
+
</div>
23
+
24
+
@code {
25
+
[Parameter]
26
+
public string Parameter1 { get; set; } = "";
27
+
}</pre>
28
+
<p>Here, <strong>SimpleChild.razor</strong> uses the <code>[Parameter]</code> attribute to define <code>Parameter1</code>, a <code>string</code> it renders within a div. This child can be reused in a parent component, <strong>SimpleParent.razor</strong>, which passes data to it:</p>
29
+
<prelanguage="razor"><div>
30
+
<h3>SimpleParent (level 0)</h3>
31
+
<SimpleChild Parameter1="@Text" />
32
+
</div>
33
+
34
+
@code {
35
+
public string Text { get; set; } = "Hello Blazor School!";
36
+
}</pre>
37
+
<p>In this example, <strong>SimpleParent.razor</strong> (Level 0) passes the value of <code>Text</code> to <strong>SimpleChild.razor</strong> (Level 1) via the <code>Parameter1</code>parameter. When rendered, <strong>SimpleChild.razor</strong> displays "Hello Blazor School!" within its <code>div</code>, demonstrating how parent to child communication enables the child to render dynamic data from the parent, aligning with the hierarchical structure previously introduced.</p>
38
+
<h3>When Not to Use the <code>[Parameter]</code> Attribute?</h3>
39
+
<p>While the <code>[Parameter]</code> attribute is effective for direct parent-child communication in Blazor, it becomes cumbersome when passing data beyond adjacent levels, such as from Level 0 to Level 2 in a 3-level hierarchy. In these cases, developers should opt for alternative communication methods to avoid unnecessary complexity.</p>
40
+
<p>Consider the following scenario, illustrated in the diagram:</p>
<p>Here, <strong>Component3 </strong>needs a parameter from <strong>Component1</strong>, but<strong> Component2</strong> doesn’t require it. Using <code>[Parameter]</code> would force the parameter to be passed through <strong>Component2</strong>: <strong>Component1 </strong> passes to <strong>Component2</strong>, which must declare the parameter just to forward it to <strong>Component3</strong>. This "prop drilling" creates 2 issues: <strong>Component2</strong> becomes cluttered with unused parameters, and in larger hierarchies with 5 or more levels, managing multiple parameters this way becomes unmaintainable.</p>
43
+
<p>In such cases, using <code>CascadingParameter</code> will allow developers to pass a parameter from Level 0 to Level 2 directly without flowing through Level 1.</p>
44
+
<hrclass="my-4" />
45
+
<h1>Communication Between Components at the Same Level</h1>
46
+
<p>Previously, we explored communication within nested components, such as parent-child relationships. In this section, we are discussing the communication of components at the same laevel, such as siblings or unrelated components. The following image shows an example of sibling components:</p>
<p>In Blazor, components at the same level may not always share the same parent—sometimes one is nested while the other is not, as shown below:</p>
<p>Here, <strong>Component2</strong> and <strong>Component3</strong> need to share data, despite <strong>Component2</strong> being nested within <strong>Component1</strong>. Using <code>CascadingParameter</code> and <code>CascadingValue</code>, you can pass data across these components without prop drilling through intermediate levels.</p>
81
+
<p><strong>Component2.razor</strong></p>
82
+
<prelanguage="razor"><div>
83
+
<h3>Component2 (level 1)</h3>
84
+
<div>@HelloMessage</div>
85
+
</div>
86
+
87
+
@code {
88
+
[Parameter]
89
+
public string HelloMessage { get; set; } = "";
90
+
}</pre>
91
+
<p><strong>Component1.razor</strong></p>
92
+
<prelanguage="razor"><div>
93
+
<h3>Component1 (level 0)</h3>
94
+
<div>@PersonName:</div>
95
+
<Component2 />
96
+
</div>
97
+
98
+
@code {
99
+
[CascadingParameter(Name = "CurrentUserName")]
100
+
public string PersonName { get; set; } = "";
101
+
}</pre>
102
+
<p><strong>Component3.razor</strong></p>
103
+
<prelanguage="razor"><div>
104
+
<h3>Component3 (level 0)</h3>
105
+
<div>@PersonName: @HelloMessage I am @PersonName.</div>
106
+
</div>
107
+
108
+
@code {
109
+
[CascadingParameter(Name = "SayHelloMessage")]
110
+
public string HelloMessage { get; set; } = "";
111
+
112
+
[CascadingParameter(Name = "CurrentUserName")]
113
+
public string PersonName { get; set; } = "";
114
+
}</pre>
115
+
<hrclass="my-4" />
116
+
<h1>Single source of truth</h1>
117
+
<p>In Blazor, using <code>Parameter</code> or <code>CascadingParameter</code> to pass data results in each component holding its own copy of the parameter. If those copies are not synchronised, they may become out of sync, and all the components will have a parameter with different values. We will walk you through how to synchronise those copies of parameters in the next tutorials. For now, this section introduces a single source of truth approach, ideal for scenarios where your application needs a single, consistent instance of data across all components. This method suits features like:</p>
118
+
<ul>
119
+
<li><strong>Login Information</strong>: Ensuring all components reflect the same user session state.</li>
120
+
<li><strong>App’s Current Settings</strong>: Maintaining uniform settings, such as theme or language, throughout the app.</li>
121
+
</ul>
122
+
<p>To implement a single source of truth in Blazor, you can follow 3 steps:</p>
123
+
<ol>
124
+
<li>
125
+
<div><strong>Create the Transfer Service</strong>: Define a service class to hold shared properties, including a private backing field and an event to notify subscribers of changes:</div>
126
+
</li>
127
+
</ol>
128
+
<prelanguage="csharp">public class BlazorSchoolTransferService
public event EventHandler<string>? HelloMessageChanged;
143
+
}</pre>
144
+
<p>Here, <code>HelloMessage</code> uses a backing field (<code>_helloMessage</code>) rather than an auto-property, allowing the service to raise the <code>HelloMessageChanged</code> event whenever the value updates.</p>
145
+
<olstart="2">
146
+
<li>
147
+
<div><strong>Register the Service</strong>: Add the service to the dependency injection container in <code>Program.cs</code>:</div>
<h3>When Single Source of Truth is Not Suitable?</h3>
176
+
<p>There are some scenarios where a single source of truth is not suitable:</p>
177
+
<ul>
178
+
<li><strong>Properties That Don’t Need to Be Shared</strong>: When a component’s state is isolated and only relevant to itself, like a counter in a single UI element or a form field’s temporary value. Using a single source of truth in such cases introduces unnecessary overhead. </li>
179
+
<li><strong>Simple Parent-Child Data Flow</strong>: If a property only needs to be shared between 2 adjacent levels, like a parent and its direct child, using <code>Parameter</code> or <code>CascadingParameter</code> is more efficient. For example, passing a message from <code>SimpleParent</code> to <code>SimpleChild</code> (as shown earlier) doesn’t require a service, as the data flow is direct and doesn’t benefit from app-wide centralisation.</li>
Copy file name to clipboardExpand all lines: contents/tutorials/component-reusability/v1/index.html
+5-2Lines changed: 5 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -8,7 +8,7 @@
8
8
</ul>
9
9
<hrclass="my-4" />
10
10
<h1>What is a Reusable Component?</h1>
11
-
<p>A component is intended to be created once and used multiple times to eliminate the need for repeating code. A component does not always need to look the same. </p>
11
+
<p>A component is intended to be created once and used multiple times to eliminate the need for repeating code. A component does not always need to look the same.</p>
12
12
<p>For example, consider you have a textbox with a label to collect input from the user. The textbox will be used in many places to collect user data. To make a component that can be used in multiple scenarios, a meaningful label should be used in each place, making every textbox in your app "slightly different". You can declare these "slight differences" as component parameters to allow them to be changed when needed. Not only do these parameters allow changing the shape of a component, but they also provide a way to enable component communication.</p>
13
13
<p>Consider a textbox to capture user input and validate user input as they type (logic). When the user inputs invalid data, the textbox appears with a red border (styling) and turns green when the data is valid. Both logic and styling of a component can be declared and reused in a component. The logic is preserved in the <code>.razor</code> file, where CSS styling is scoped in the <code>.razor.css</code> file.</p>
14
14
<hrclass="my-4" />
@@ -20,7 +20,10 @@ <h1>How to Build a Reusable Component?</h1>
20
20
<p>Create a new Razor Component by right-clicking a folder within your project in Visual Studio and selecting <strong>Add</strong> > <strong>Razor Component... </strong>and name it—e.g., <code>BlazorSchoolInputText.razor</code></p>
0 commit comments