Blazor 데이터 바인딩 관련

[코드 요약]
class buliding {
string name
string address

string a1
string a2
string a3

string c1
string c2
string c3
}

[ razor 구조 : main.razor() → info.razor → groupinput.razor(3개를 받음) ]

  1. [main]에서 객체를 생성 후 로 전달

  2. [info]에서 [Paramter]public Building Building로 받아서 아래처럼 선언
    [GroupInput
    value1=@Building.a1
    value2=@Building.a2
    value3=@Building.a3 />

3.[<Group]에서는 내부에 있는 input에서 bind
<input @bind-Value = value1/>
<input @bind-Value = value2/>
<input @bind-Value = value3/>

[문제점]

  1. 에서Building을 디버그로 찍으면 null값이 나옴
  2. 에서 [parameter] value1, 2, 3를 console.writeline을찍으면 값이 나옴
  3. cascadingvalue로 name지정해서 해봤지만 안됨
  4. eventcallback을 사용하면 에서 이 8개면 8개에 대한 각 함수를 만들어야해서 아닌거같다는 생각이 들었음

해결방법있나요 ?

1 Like

중간에 자식 컴포넌트인 groupinput.razor에서 input에 넣은 @bind-Value로 바인딩 후 input 값을 바꿨는데 상위 컴포넌트인 info.razor에서 값이 바뀌지 않은 이유를 물으신 것으로 이해하고 답변드리겠습니다.

Blazor의 양방향 바인딩으로 Parameter로 받은 데이터를 상위 컴포넌트에게 전달하려면 EventCallback 또한 파라미터로 받아서 자식 컴포넌트에서 이벤트를 상위 컴포넌트에 전달하는 방식으로 진행해야 합니다. 여기서는 EventCallback<Buliding>[Parameter]로 정의하고 groupinput.razor에서 @bind-Building하는 방식으로 진행하면 됩니다.

예시 문서는 구성 요소 매개 변수를 사용하여 바인딩입니다.

2 Likes

블레이저 컴포넌트는 부모 컴포넌트가 자식 컴포넌트에게 의존하지 않도록 설계되어 있습니다. 부작용이 많기 때문이죠.

그래서, 컴포넌트가 외부 입력값을 변경시켜주는 기능은 내부적으로 다음과 같이 구현합니다:

  • 값을 받는 파라미터를 구현함.
    예시: [Parameter] public string Text { get; set; }
  • 컴포넌트에서 값을 변경하면, 외부에 변경을 알려주는 이벤트를 구현함
    예시: [Parameter] public EventCallback<string> TextChanged { get; set; }

정석적으로 부모는 다음과 같이 값 변경을 해야합니다.

<YourTextModifier Text="@name" TextChanged="@OnNameChanged" />
@code {
    string name = "kim";
    void OnNameChanged(string value)
    {
        name = value;
    }
}

좀 귀찮죠. 실제로 이런 행위가 매우 빈번할 테니까요. 작성할 내용이 늘어나게 됩니다.

그래서 블레이저는,

[Parameter] public AnyType OOO { get; set; } 
[Parameter] public EventCallback<AnyType> OOOChanged { get; set; }

정확히 위의 구조로 되어있는 컴포넌트를,

<YourTextModifier @bind-OOO="@name" />

이렇게 사용할 수 있게 구문 설탕같은 기능을 지원해줍니다.
내부적으로는 정석 방법과 똑같이 동작합니다.

따라서 GroupInput 컴포넌트에 외부에 알려주는 OOOChanged 이벤트 파라미터를 만들고, 값이 바뀌었을 때

async Task NotifyOOOChanged()
{
    await OOOChanged.InvokeAsync(바뀐값);
}

해주시면 됩니다.
그러면 GroupInput 컴포넌트의 input에는 @bind- 를 사용할수 없겠죠.


따라서 이렇게 해야합니다:

<input type="text" value="@YourValue" @onchange="@(e => OnYourValueChanged((string)e.Value))" />
@code {
    //...
    async Task OnYourValueChanged(string value)
    {
        YourValue = value;
        await YourValueChanged.InvokeAsync(value);
    }
})

더 줄이면

<input type="text" value="@YourValue" @onchange="@(e => YourValueChanged.InvokeAsync(YourValue = (string)e.Value))" />
5 Likes

정석적인 부분은 위에 고수 분들이 잘 말 해주셨는데요,
아니면 특정 데이터를 보관, 상호작용을 해 주는 Service를 구현해서
@Inject 을 활용해보시는 방향은 어떨까요?
경우에 따라선 이쪽이 구현하기에는 더 쉬우실 수도 있어요.

어떻게보면 blazor 조차도 어느정도 관점을 분리할 수 있는 장점도 있구요.
단… 약간 복잡해진다는 단점도 똑같이 있지요.

이 경우에는 부모 컨트롤에 inject 시킨 다음
cascadingparameter로 해당 서비스를 넘겨주는 방법도 가능하겠네요

1 Like