0Pricing
C# Academy · บทเรียน

การจัดการสถานะใน Blazor

จัดการสถานะร่วมด้วย singleton ของบริการ Fluxor หรือ AppState แบบส่งต่อเป็นลำดับชั้น เพื่อให้ส่วนติดต่อผู้ใช้สอดคล้องกันระหว่างคอมโพเนนต์

การจัดการสถานะใน Blazor เป็นบทเรียน C# Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C# Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

ความท้าทายในการจัดการสถานะใน Blazor

เมื่อแอป Blazor มีขนาดใหญ่ขึ้น การจัดการสถานะที่ต้องใช้ร่วมกันในคอมโพเนนต์ที่ไม่เกี่ยวข้องกันหลายตัวจะซับซ้อนขึ้น การส่งคุณสมบัติต่อกันหลายชั้นแบบง่าย ๆ เริ่มไม่เพียงพอ คุณจึงต้องมีคลังสถานะแบบรวมศูนย์ที่ตอบสนองต่อการเปลี่ยนแปลง

การจัดการสถานะแบบง่ายด้วยบริการที่มีขอบเขต

แนวทางการจัดการสถานะใน Blazor ที่ง่ายที่สุดคือใช้บริการที่มีขอบเขตเพื่อเก็บสถานะ และเปิดเหตุการณ์ให้คอมโพเนนต์สมัครรับการเปลี่ยนแปลงได้

public class CartState
{
    private readonly List<CartItem> _items = new();
    public IReadOnlyList<CartItem> Items => _items;
    public int Count => _items.Sum(i => i.Quantity);

    public event Action? OnChanged;

    public void Add(Product p)
    {
        var existing = _items.FirstOrDefault(i => i.ProductId == p.Id);
        if (existing is not null) existing.Quantity++;
        else _items.Add(new CartItem { ProductId = p.Id, Name = p.Name, Price = p.Price });
        OnChanged?.Invoke();
    }
}

การสมัครรับการเปลี่ยนแปลงสถานะ

คอมโพเนนต์สมัครรับเหตุการณ์ OnChanged ของบริการสถานะ แล้วเรียก StateHasChanged เพื่อแสดงผลใหม่ อย่าลืมยกเลิกการสมัครรับใน Dispose

@inject CartState Cart
@implements IDisposable

<p>Cart: @Cart.Count items</p>

@code {
    protected override void OnInitialized()
    {
        Cart.OnChanged += OnCartChanged;
    }

    private void OnCartChanged()
    {
        InvokeAsync(StateHasChanged);
    }

    public void Dispose() =>
        Cart.OnChanged -= OnCartChanged;
}

CascadingValue ในฐานะตัวเก็บสถานะ

ครอบเค้าโครงรากของแอปด้วย CascadingValue ที่มีบริการสถานะของคุณ คอมโพเนนต์ลูกหลานทั้งหมดจะเข้าถึงบริการนี้ได้โดยไม่ต้องส่งคุณสมบัติผ่านกันอย่างชัดเจน

@* MainLayout.razor *@
@inject CartState Cart

<CascadingValue Value="Cart">
    @Body
</CascadingValue>

@* Any nested component: *@
@code {
    [CascadingParameter]
    public CartState Cart { get; set; } = default!;

    private void Buy(Product p) => Cart.Add(p);
}

Fluxor: รูปแบบ Flux สำหรับ Blazor

Fluxor นำการไหลของข้อมูลทิศทางเดียวแบบ Redux มาสู่ Blazor: สถานะ → คอมโพเนนต์ → การกระทำ → ตัวลดรูป → สถานะ เหมาะอย่างยิ่งสำหรับแอปพลิเคชันที่ซับซ้อน

// dotnet add package Fluxor.Blazor.Web

// State record
[FeatureState]
public record CounterState(int Count = 0);

// Actions
public record IncrementAction(int Amount = 1);

// Reducers
public static class CounterReducers
{
    [ReducerMethod]
    public static CounterState Reduce(CounterState state, IncrementAction action)
        => state with { Count = state.Count + action.Amount };
}

// Registration:
builder.Services.AddFluxor(opt =>
    opt.ScanAssemblies(typeof(Program).Assembly));

การใช้ Fluxor ในคอมโพเนนต์

ฉีด IState<T> เพื่ออ่านสถานะ และฉีด IDispatcher เพื่อส่งการกระทำ InheritsFrom<FluxorComponent> (หรือมิกซ์อิน) จะสมัครรับการเปลี่ยนแปลงสถานะโดยอัตโนมัติ

@inherits FluxorComponent
@inject IState<CounterState> CounterState
@inject IDispatcher Dispatcher

<p>Count: @CounterState.Value.Count</p>
<button @onclick="Increment">+1</button>
<button @onclick="() => Dispatcher.Dispatch(new IncrementAction(5))">+5</button>

@code {
    private void Increment()
        => Dispatcher.Dispatch(new IncrementAction(1));
}

การคงสถานะใน LocalStorage

คงสถานะไว้ข้ามการรีเฟรชหน้าโดยใช้ localStorage ของเบราว์เซอร์ผ่านการเชื่อมการทำงานกับ JavaScript แล้วกู้คืนสถานะเมื่อแอปเริ่มต้น

@inject IJSRuntime JS

@code {
    private async Task SaveStateAsync()
    {
        var json = JsonSerializer.Serialize(_state);
        await JS.InvokeVoidAsync("localStorage.setItem", "appState", json);
    }

    protected override async Task OnInitializedAsync()
    {
        var json = await JS.InvokeAsync<string?>("localStorage.getItem", "appState");
        if (json is not null)
            _state = JsonSerializer.Deserialize<AppState>(json) ?? new();
    }

    private AppState _state = new();
}

แพ็กเกจ Blazored.LocalStorage

แพ็กเกจ Blazored.LocalStorage มี API แบบมีชนิดข้อมูลที่ใช้งานง่ายสำหรับ localStorage ของเบราว์เซอร์ โดยไม่ต้องเขียนการเรียกใช้ JS interop ด้วยตนเอง

// dotnet add package Blazored.LocalStorage
builder.Services.AddBlazoredLocalStorage();

@inject ILocalStorageService LocalStorage

@code {
    protected override async Task OnInitializedAsync()
    {
        _cart = await LocalStorage.GetItemAsync<List<CartItem>>("cart") ?? new();
    }

    private async Task SaveCartAsync()
    {
        await LocalStorage.SetItemAsync("cart", _cart);
    }

    private List<CartItem> _cart = new();
}

สถานะ URL ด้วย NavigationManager

ใช้พารามิเตอร์ของ query เพื่อเก็บสถานะที่ควรอยู่ต่อหลังรีเฟรชหน้าและสามารถบันทึกเป็นบุ๊กมาร์กได้ อ่านและเขียนพารามิเตอร์เหล่านี้ผ่าน NavigationManager และตัวสร้าง URI

@inject NavigationManager Nav
@page "/products"

@code {
    [SupplyParameterFromQuery] public string? Search { get; set; }
    [SupplyParameterFromQuery] public int Page { get; set; } = 1;

    private void UpdateSearch(string s)
    {
        Nav.NavigateTo(
            Nav.GetUriWithQueryParameters(
                new Dictionary<string, object?>
                {
                    [nameof(Search)] = s,
                    [nameof(Page)]   = 1
                }));
    }
}

ตัวอย่างจริง: สถานะตะกร้าสินค้า

รูปแบบที่สมบูรณ์: บริการ CartState แบบมีขอบเขตที่มีเหตุการณ์ คงสถานะไว้ใน localStorage เมื่อมีการเปลี่ยนแปลง และกู้คืนเมื่อโหลด

public class CartState
{
    private readonly ILocalStorageService _storage;
    private List<CartItem> _items = new();
    public event Action? OnChanged;

    public CartState(ILocalStorageService storage) => _storage = storage;

    public async Task InitAsync()
    {
        _items = await _storage.GetItemAsync<List<CartItem>>("cart") ?? new();
    }

    public async Task AddAsync(Product p)
    {
        var item = _items.FirstOrDefault(i => i.ProductId == p.Id);
        if (item is not null) item.Quantity++;
        else _items.Add(new CartItem { ProductId = p.Id, Name = p.Name });
        await _storage.SetItemAsync("cart", _items);
        OnChanged?.Invoke();
    }
}

ตรวจสอบความเข้าใจอย่างรวดเร็ว

แนวทางการจัดการสถานะแบบใดเหมาะที่สุดสำหรับแอป Blazor แบบง่ายที่มีสถานะร่วมกันจำกัด

สรุป: การจัดการสถานะใน Blazor

ประเด็นสำคัญ:

  • บริการแบบมีขอบเขต + เหตุการณ์การกระทำ: สถานะร่วมกันที่ง่ายที่สุดและเหมาะกับแอปส่วนใหญ่
  • การครอบเค้าโครงรากด้วย CascadingValue ช่วยให้เข้าถึงได้ทั่วทั้งแอปโดยไม่ต้องส่งคุณสมบัติผ่านหลายชั้น
  • Fluxor: การไหลของข้อมูลทิศทางเดียวแบบ Redux สำหรับตรรกะสถานะที่ซับซ้อน
  • คงสถานะไว้ใน localStorage ด้วย IJSRuntime หรือ Blazored.LocalStorage
  • สถานะ URL (SupplyParameterFromQuery) สำหรับสถานะส่วนติดต่อผู้ใช้ที่ทำเป็นบุ๊กมาร์กและแชร์ได้
  • ยกเลิกการสมัครรับเหตุการณ์ใน Dispose เสมอ เพื่อป้องกันการรั่วไหลของหน่วยความจำ

คำถามที่พบบ่อย

บทเรียน “การจัดการสถานะใน Blazor” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การจัดการสถานะใน Blazor” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C# Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C# Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การจัดการสถานะใน Blazor”

จัดการสถานะร่วมด้วย singleton ของบริการ Fluxor หรือ AppState แบบส่งต่อเป็นลำดับชั้น เพื่อให้ส่วนติดต่อผู้ใช้สอดคล้องกันระหว่างคอมโพเนนต์ คุณปฏิบัติ C# Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C# Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C# Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “การจัดการสถานะใน Blazor” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C# Academy นี้ได้ไหม

ได้ บทเรียน C# Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. รูปแบบคอมโพเนนต์ของ Blazor
  2. การผูกข้อมูลและการจัดการเหตุการณ์
  3. การสื่อสารระหว่างคอมโพเนนต์และ DI
  4. การจัดการสถานะใน Blazor
← กลับไปที่ C# Academy