연습 - Blazor 애플리케이션에서 데이터 공유

완료됨

이제 사용자의 앱이 데이터베이스에 연결되었으므로 고객이 피자를 주문하고 구성하는 기능을 추가할 차례입니다.

Blazing Pizza는 고객이 스페셜 피자의 사이즈를 변경할 수 있는 기능을 구축하도록 요구하고 있습니다. 주문을 저장해야 하며 컨테이너 서비스에 애플리케이션 상태를 저장하도록 선택했습니다.

이 연습에서는 새 주문 구성 요소에 데이터를 전달하고 OrderState 범위가 지정된 서비스에서 앱의 상태를 저장하는 방법을 확인합니다.

새 주문 구성 대화 상자 추가

  1. 앱이 계속 실행되고 있으면 중지합니다.

  2. Visual Studio Code에서 Shared 폴더를 마우스 오른쪽 단추로 클릭하고 새 파일을 선택합니다.

  3. 파일 이름으로 ConfigurePizzaDialog.razor를 입력합니다.

  4. 새 주문 구성 요소의 UI에 대해 다음 코드를 입력합니다.

    @inject HttpClient HttpClient
    
    <div class="dialog-container">
        <div class="dialog">
            <div class="dialog-title">
                <h2>@Pizza.Special.Name</h2>
                @Pizza.Special.Description
            </div>
            <form class="dialog-body">
                <div>
                    <label>Size:</label>
                    <input type="range" min="@Pizza.MinimumSize" max="@Pizza.MaximumSize" step="1" />
                    <span class="size-label">
                        @(Pizza.Size)" (£@(Pizza.GetFormattedTotalPrice()))
                    </span>
                </div>
            </form>
    
            <div class="dialog-buttons">
                <button class="btn btn-secondary mr-auto" >Cancel</button>
                <span class="mr-center">
                    Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
                </span>
                <button class="btn btn-success ml-auto" >Order ></button>
            </div>
        </div>
    </div>
    

    이 구성 요소는 선택된 스페셜 피자를 표시하고 고객이 피자 사이즈를 선택할 수 있도록 하는 대화 상자입니다.

    구성 요소에는 피자의 멤버 값에 액세스하기 위해 인덱스 페이지 구성 요소의 스페셜 피자가 필요합니다.

  5. 매개 변수를 구성 요소에 전달할 수 있도록 Blazor @code 블록을 추가합니다.

    @code {
        [Parameter] public Pizza Pizza { get; set; }
    }
    

피자 주문

고객이 피자를 선택하면 대화 상자에서 피자 사이즈를 변경할 수 있어야 합니다. index.razor 컨트롤을 개선하여 이 대화형 작업을 추가해 보겠습니다.

  1. 파일 탐색기에서 페이지를 확장한 다음, index.razor를 선택합니다.

  2. @code 블록의 List<PizzaSpecial> 변수 아래에 다음 코드를 추가합니다.

        Pizza configuringPizza;
        bool showingConfigureDialog;
    
  3. OnInitializedAsync() 메서드 아래에 피자를 만드는 코드를 추가합니다.

        void ShowConfigurePizzaDialog(PizzaSpecial special)
        {
            configuringPizza = new Pizza()
            {
                Special = special,
                SpecialId = special.Id,
                Size = Pizza.DefaultSize
            };
    
            showingConfigureDialog = true;
        }
    
  4. 고객이 피자의 <li> 태그를 선택할 수 있도록 하여 웹 페이지가 서버 쪽 ShowConfigurePizzaDialog 메서드를 호출하도록 허용합니다. <li> 줄을 다음 코드로 바꿉니다.

    <li @onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
    

    고객이 피자를 선택하면 서버는 스페셜 피자 데이터를 사용하여 피자를 만들고 showingConfigureDialog 변수를 true로 설정하는 ShowConfigurePizzaDialog 메서드를 실행합니다.

  5. 페이지에는 새 ConfigurePizzaDialog 구성 요소를 표시하는 방법이 필요합니다. @code 블록 바로 위에 다음 코드를 추가합니다.

    @if (showingConfigureDialog)
    {
        <ConfigurePizzaDialog Pizza="configuringPizza" />
    }
    

    이제 전체 index.razor 파일은 다음 예제와 같이 표시됩니다.

        @page "/"
        @inject HttpClient HttpClient
        @inject NavigationManager NavigationManager
    
        <div class="main">
          <h1>Blazing Pizzas</h1>
          <ul class="pizza-cards">
            @if (specials != null)
            {
              @foreach (var special in specials)
              {
                <li @onclick="@(() => ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
                  <div class="pizza-info">
                  <span class="title">@special.Name</span>
                  @special.Description
                  <span class="price">@special.GetFormattedBasePrice()</span>
                  </div>
                </li>
              }
            }
          </ul>
        </div>
    
        @if (showingConfigureDialog)
        {
            <ConfigurePizzaDialog Pizza="configuringPizza" />
        }
    
        @code {
          List<PizzaSpecial> specials = new();
          Pizza configuringPizza;
          bool showingConfigureDialog;
    
          protected override async Task OnInitializedAsync()
          {
              specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
          }
    
          void ShowConfigurePizzaDialog(PizzaSpecial special)
          {
              configuringPizza = new Pizza()
              {
                  Special = special,
                  SpecialId = special.Id,
                  Size = Pizza.DefaultSize
              };
    
              showingConfigureDialog = true;
          }
        }
    
  6. F5를 선택하거나 실행을 선택합니다. 그런 다음, 디버깅 시작을 선택합니다.

  7. 피자를 선택하고 표시되는 새 대화 상자를 관찰합니다.

    피자 주문 대화 상자를 보여주는 스크린샷.

주문 상태 처리

현재, 앱은 구성 대화 상자를 표시하지만 피자를 취소하거나 피자 주문으로 이동할 수는 없습니다. 주문 상태를 관리하려면 새 주문 상태 컨테이너 서비스를 추가합니다.

  1. 앱이 계속 실행되고 있으면 중지합니다.

  2. BlazingPizza 폴더에 새 폴더를 만듭니다. 이름을 Services로 지정합니다.

  3. Services 폴더에 새 파일을 만듭니다. 이름을 OrderState.cs로 지정합니다.

  4. 클래스에 대해 다음 코드를 입력합니다.

    namespace BlazingPizza.Services;
    
    public class OrderState
    {
        public bool ShowingConfigureDialog { get; private set; }
        public Pizza ConfiguringPizza { get; private set; }
        public Order Order { get; private set; } = new Order();
    
        public void ShowConfigurePizzaDialog(PizzaSpecial special)
        {
            ConfiguringPizza = new Pizza()
            {
                Special = special,
                SpecialId = special.Id,
                Size = Pizza.DefaultSize,
                Toppings = new List<PizzaTopping>(),
            };
    
            ShowingConfigureDialog = true;
        }
    
        public void CancelConfigurePizzaDialog()
        {
            ConfiguringPizza = null;
    
            ShowingConfigureDialog = false;
        }
    
        public void ConfirmConfigurePizzaDialog()
        {
            Order.Pizzas.Add(ConfiguringPizza);
            ConfiguringPizza = null;
    
            ShowingConfigureDialog = false;
        }
    }
    

    현재 index.razor 구성 요소에 새 클래스로 이동할 수 있는 코드가 있음을 알 수 있습니다. 다음 단계는 앱에서 이 서비스를 사용할 수 있도록 하는 것입니다.

  5. 파일 탐색기에서 Program.cs를 선택합니다.

  6. builder.Services.로 시작하는 줄이 있는 파일 부분에 다음 줄을 추가합니다.

    builder.Services.AddScoped<OrderState>();
    

    이전 연습에서는 여기에 데이터베이스 컨텍스트를 추가했습니다. 이 코드는 새 OrderState 서비스를 추가합니다. 이 코드가 있으면 이제 index.razor 구성 요소에서 사용할 수 있습니다.

  7. 다음 using 지시문을 파일의 맨 위에 추가하여 OrderState 클래스를 확인합니다.

    using BlazingPizza.Services;
    
  8. 파일 탐색기에서 페이지를 확장한 다음, index.razor를 선택합니다.

  9. 파일 맨 위에 있는 @inject NavigationManager NavigationManager 아래에 다음 코드를 추가합니다.

    @using BlazingPizza.Services
    @inject OrderState OrderState
    
  10. @code 블록에서 configuringPizza, showingConfigureDialog, ShowConfigurePizzaDialog()를 제거합니다. 이제 다음과 같이 표시됩니다.

    @code {
        List<PizzaSpecial> specials = new List<PizzaSpecial>();
    
        protected override async Task OnInitializedAsync()
        {
            specials = await HttpClient.GetFromJsonAsync<List<PizzaSpecial>>(NavigationManager.BaseUri + "specials");
        }
    }
    

    이제 모든 코드가 삭제된 항목을 참조하는 오류가 있습니다.

  11. OrderState 버전을 사용하도록 ShowConfigurePizzaDialog(special)) 호출을 변경합니다.

    <li @onclick="@(() => OrderState.ShowConfigurePizzaDialog(special))" style="background-image: url('@special.ImageUrl')">
    
  12. 부울 showingConfigureDialog에 대한 참조를 변경합니다.

    @if (OrderState.ShowingConfigureDialog)
    
  13. configuringPizza를 사용하여 매개 변수를 변경합니다.

    <ConfigurePizzaDialog Pizza="OrderState.ConfiguringPizza" />
    
  14. F5를 선택하거나 실행을 선택합니다. 그런 다음, 디버깅 시작을 선택합니다.

    모든 것이 올바르면 아무런 차이가 나타나지 않습니다. 대화 상자는 이전과 같이 표시됩니다.

피자 주문 취소 및 만들기

OrderState 클래스에서 아직 사용하지 않은 두 메서드가 있다는 것을 알아차렸을 것입니다. CancelConfigurePizzaDialogConfirmConfigurePizzaDialog 메서드는 고객이 주문을 확인하면 대화 상자를 닫고 Order 개체에 피자를 추가합니다. 이러한 메서드를 구성 대화 상자 단추에 연결해 보겠습니다.

  1. 앱이 계속 실행되고 있으면 중지합니다.

  2. 파일 탐색기에서 공유를 확장합니다. 그런 다음, ConfigurePizzaDialog.razor를 선택합니다.

  3. @code 블록에서 다음과 같이 두 개의 새 매개 변수를 추가합니다.

      @code {
        [Parameter] public Pizza Pizza { get; set; }
        [Parameter] public EventCallback OnCancel { get; set; }
        [Parameter] public EventCallback OnConfirm { get; set; }
      }
    
  4. 이제 단추에 @onclick 지시문을 추가할 수 있습니다. 대화 상자 단추의 현재 코드를 다음 태그로 변경합니다.

      <div class="dialog-buttons">
          <button class="btn btn-secondary mr-auto" @onclick="OnCancel">Cancel</button>
          <span class="mr-center">
              Price: <span class="price">@(Pizza.GetFormattedTotalPrice())</span>
          </span>
          <button class="btn btn-success ml-auto" @onclick="OnConfirm">Order ></button>
      </div>
    
  5. 마지막 단계는 주문을 취소 및 확인하기 위한 OrderState 메서드를 전달하는 것입니다. 파일 탐색기에서 페이지를 확장합니다. 그런 다음, Index.razor를 선택합니다.

  6. ConfigurePizzaDialog 구성 요소를 호출하기 위한 코드를 변경합니다.

        <ConfigurePizzaDialog
          Pizza="OrderState.ConfiguringPizza"
          OnCancel="OrderState.CancelConfigurePizzaDialog"
          OnConfirm="OrderState.ConfirmConfigurePizzaDialog" />
    
  7. F5를 선택하거나 실행을 선택합니다. 그런 다음, 디버깅 시작을 선택합니다.

이제 앱에서 고객이 주문에서 구성된 피자를 취소하거나 추가할 수 있습니다. 피자 사이즈가 변경되면 현재 주문을 표시하거나 가격을 업데이트할 방법이 없습니다. 다음 연습에서는 이러한 기능을 추가합니다.