在没有触发器的情况下,如何将值从子级传递给父级?

问题描述 投票:0回答:2

我有一个带有子组件的父组件

<h3>Parent component</h3>
<Child />

孩子有孙子

<h3>Child component</h3>
<Grandchild @bind-SelectedVariant="_selectedVariant" />
<h4>Costs: @GetCosts()</h4>

GetCosts()
取决于
_selectedVariant

孙子是

<h3>Grandchild component</h3>
<input type="checkbox" @onclick="(e) => ToggleCheckboxAsync("Variant 1")" />

@code {
    [Parameter] public string SelectedVariant { get; set; } = "";
    [Parameter] public EventCallback<string> SelectedVariantChanged { get; set; }
    private async Task OnSelectedVariantChange(string selectedVariant) => await SelectedVariantChanged.InvokeAsync(selectedVariant);

    private async Task ToggleCheckboxAsync(string clickedVariantName)
    {
        await OnSelectedVariantChange(clickedVariantName);
        StateHasChanged();
    }
}

这个效果很好。当我切换复选框时,显示的成本会更新。 (仅在选中复选框时,因为本示例中未实现取消选中。)
我发现,我需要父组件中的成本。所以,我的第一次尝试是通过 EventCallback 添加另一个绑定:

<h3>Child component</h3>
<Grandchild @bind-SelectedVariant="_selectedVariant" />
<h4>Costs: @GetCosts()</h4>

@code {
    [Parameter, EditorRequired] public int Costs { get; set; } = -1;
    [Parameter] public EventCallback<int> CostsChanged { get; set; }
    private async Task OnCostsChange() => await CostsChanged.InvokeAsync(Costs);
}

<h3>Parent component</h3>
<Child @bind-Costs="_costs" />

但是我如何触发

OnCostsChange()
?使用
OnSelectedVariantChange()
很容易,因为这只是复选框的单击事件。

data-binding blazor-webassembly
2个回答
0
投票

由于 Child 组件中没有触发器,我认为

OnCostsChange()
没有任何意义,
Costs
&
EventCallback<int> CostsChanged
属性足以进行双向绑定。有关更多详细信息,您可以查看此 document

如果你想从父组件中调用子组件中的方法,你可以尝试:

<Child @bind-Costs="_costs" @ref="Child"/>

<button @onclick="TriggerChildMethod">Button</button>

@code{
    public int _costs;

    private Child Child { get; set; }

    public async Task TriggerChildMethod()
    {
            await Child.SomeMethod();
    }
}

在子组件中:

public async Task SomeMethod() {......}

0
投票

我认为你可能有点过于复杂化了。如果您打算将值从父级传递给子级,则只需要进行双向绑定。如果孩子执行一些逻辑来得出该值,则只需使用回调即可。

这是我的

Grandchild
。我猜现实中有多种变体,所以我就这样编码了。

<h3>Grandchild component</h3>
<input type="checkbox" @bind:get="@(IsChecked("Variant 1"))" @bind:set="@((e) => ToggleCheckboxAsync("Variant 1"))" />

@code {
    [Parameter] public string SelectedVariant { get; set; } = string.Empty;
    [Parameter] public EventCallback<string> SelectedVariantChanged { get; set; }

    private bool IsChecked(string value)
        => SelectedVariant == value;

    private async Task ToggleCheckboxAsync(string value)
    {
        if (this.IsChecked(value))
            await this.SelectedVariantChanged.InvokeAsync(string.Empty);
        else
            await this.SelectedVariantChanged.InvokeAsync(value);

        // not required
        //StateHasChanged();
    }
}

然后孩子:

<h3>Child component</h3>

<GrandChild @bind-SelectedVariant:get="_selectedVariant" @bind-SelectedVariant:set="this.OnVariantChanged" />

<h4>Costs: @_costs</h4>

@code {
    // this is a calcuated value, not set from the parent
    // Parameter, EditorRequired] public int Costs { get; set; } = -1;
    [Parameter] public EventCallback<int> CostsChanged { get; set; }

    private int _costs;
    private string _selectedVariant = string.Empty;

    private async Task OnVariantChanged(string value)
    {
        _selectedVariant = value;
        _costs = Random.Shared.Next(5,25);
        if (value.Equals("Variant 1"))
            _costs = _costs + 100;

        await this.CostsChanged.InvokeAsync(_costs);
    }
}

还有家:

@page "/"

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

<Child CostsChanged="this.OnCostsChanged" />

<div class="bg-dark text-white m-2 p-2">
    <pre>Costs: @_costs</pre>
</div>

@code{
    private int _costs;

    private Task OnCostsChanged(int value)
    {
        _costs = value;
        return Task.CompletedTask;
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.