Blazor:从父组件向子组件传递数据

9

我有一个 Razor 页面,它依赖于其父类和第二个子类,第二个子类有自己的类并从其父类接收数据,我的问题是在第二次调用 API 时,数据没有传递给第二个子类,在其父类更改数据时第二个子类不会被渲染,但在第一次渲染时它可以正常工作并传递数据。

Parent.razor

@inherits ParentBase;

<FirstChild/>
<SecondChild data="@data"/>

FirstChild.razor

@inherits ParentBase;

// call its parent method
<span  @onclick='(() => callApi())'/> 

ParentBase.cs

public class ParentBase : ComponentBase
{
   public Data data { get; set; }
   protected override async Task OnInitializedAsync()
   {
       data = await Services.GetData();
   }
   // call from a child
   public void callApi
   {
     data = await Services.GetData();
   }
}

SecondChild.razor

<Table data="@data"/>

SecondChildBase.cs

public class SecondChildBase : ComponentBase
{
   [Parameter]
   public Data data { get; set; }

   protected override void OnParametersSet()
   {
       // this is not getting called
       StateHasChanged();
       Console.WriteLine(data);
   }
}
3个回答

5
Parent.razorFirstChild.razor继承自同一类,并不意味着两个类的数据(public Data data { get; set; })在更改时具有相同的值。
当在FirstChild中调用callApi时,它将更改自己的data。如果您想更改父级的data,则需要向FirstChild传递一个参数,该参数将是一个在单击span时调用并调用ParentcallApi函数的函数。 FirstChild.razor
<span @onclick="OnClick">Call Parent function</span>

@code 
{
    // Call this EventCallback when the span is clicked
    [Parameter]
    public EventCallback OnClick { get; set; }
}

Parent.razor

@inherits ParentBase;

@* Passing OnClick Parameter to call callApi*@
<FirstChild OnClick="@callApi" />
<SecondChild data="@data" />

1
感谢您的快速回复,我继承父类的原因是为了避免使用EventCallback,因为我有很多来自不同子类的API调用,如果子类嵌套在另一个子类中,传递EventCallback会很困难。 - Ahmed Imam
1
对于这个实例,我有另一个子元素位于第二个子元素内部,需要调用API并更改数据,最好的方法是什么?谢谢。 - Ahmed Imam
2
@AhmedImam 如果你想让多个子组件都能够访问该函数,而不想将参数传递给所有子组件,你可以使用 CascadingValue 或创建类似于“服务”的东西。如果你想了解更多信息,请阅读这篇文章 - Vencovsky
1
在这里使用+1级联参数.. 这是正确的方法.. 我会在子组件中给你“父级”的实例,这样你就可以直接调用它。 - Robert Perry

4
我认为你可以尝试使用数据绑定,而不是级联参数。
文档在这里: https://learn.microsoft.com/en-us/aspnet/core/blazor/data-binding?view=aspnetcore-3.1 特别是以下两个主题:
  • 使用组件参数进行从父组件到子组件的绑定
  • 使用链接绑定进行从子组件到父组件的绑定
示例:父组件。
<PasswordField @bind-Password="password" />

@code {
    private string password;
}

示例:子组件

<input @oninput="OnPasswordChanged" 
       required 
       type="@(showPassword ? "text" : "password")" 
       value="@Password" />

@code {
    private bool showPassword;
    private string password;
    private string validationMessage;

    [Parameter]
    public string Password
    {
        get { return password ?? string.Empty; }
        set
        {
            if (password != value)
            {
                if (value.Contains(' '))
                {
                    validationMessage = "Spaces not allowed!";
                }
                else
                {
                    password = value;
                    validationMessage = string.Empty;
                }
            }
        }
    }

    [Parameter]
    public EventCallback<string> PasswordChanged { get; set; }

    private Task OnPasswordChanged(ChangeEventArgs e)
    {
        Password = e.Value.ToString();

        return PasswordChanged.InvokeAsync(Password);
        }

    }

您的子组件需要提供一个{Password}Changed函数,其中{}是您的参数。这样,当子组件更新时,父组件以及所有其他绑定参数也会被更新。


1

只需将StateHasChanged()移至服务调用之后的基类即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接