블레이저 데이터 바인딩.

간만에 까먹고… 쌩고생했습니다. ㅠㅠ

class Foo
{
    public string Bar { get; set; } = string.Empty();
}
//MyPage.razor

private Foo[] _foos ...

//...
for(int i = 0; i < _foos.Length ; i++)
{
    <input type="text" @bind-value="@_foos[i].Bar" .... />
}
4 Likes

오잉? 뭐가 잘못된건가요??

3 Likes

IndexOutOfRangeException 이 발생합니다.

아직 만나지 않으셨다니… 다행입니다. ^^

4 Likes

저도 얼핏 봐서 제대로 이해를 못 해서 그런가 쬐끔 신기하게 느껴졌네요.
_foos 가 초기화 된 걸로 보이지 않아서, NullReferenceException가 뜬다고 생각이 들었거든요.

헌데 보통 blazor에서는 for말고 foreach를 가 쬐금 더 권장 되는 듯 한데 그건 어떨까요?
나열되는 contol의 id에 고유번호를 넣는다고 쳐도, 반복되는 객체에 index에 해당하는 필드 값을 넣는 게 나을 것 같기도 하고요.

1 Like

for 를 쓰면, 루프 인덱서(int i) 가 for 의 범위를 넘어 살아 남기 때문에 발생하는 문제입니다.

렌더링 직후에 i 의 값은 _foos.Length 와 같아 집니다.
데이터 바인딩은 렌더링 이후에 이뤄지기 때문에, 아래의 코드는 항상 인덱스 에러가 발행합니다.

<input type="text" @bind-value="@_foos[i].Bar" .... />  

for 대신에, foreach를 쓰는 것이 안전하지만, for 를 쓰더라도 아래와 같이 for 루프 안에 임시 변수를 만들면 문제가 없어집니다.

for(int i = 0; i < _foos.Length ; i++)
{
    var index = i;
    <input type="text" @bind-value="@_foos[index].Bar" .... />
}

혹은

for(int i = 0; i < _foos.Length ; i++)
{
    var f = _foos[i];
    <input type="text" @bind-value="@f.Bar" .... />
}

혹은

for(int i = 0; i < _foos.Length ; i++)
{
    var b = _foos[i].Bar;
    <input type="text" @bind-value="@b" .... />
}
5 Likes

말씀하신 그대로네요!
아무래도, 렌더링 쪽에서 (다행히도) for 문 쓸 일이 거의 없어서 아직 저런 문제로 골머리를 앓진 않았나 봐요.
혹은 생각 없이 쓰다가 저도 모르게 고쳐버렸을 수도 있구요. ㅎㅎㅎㅎ
꿀팁 / 경험담 너무 감사합니다!

3 Likes

예외가 발생해도 예외 메시지가 충분하면 문제를 즉각 발견할 수 있는데, 예외 메시지에 나타난 코드가 블레이저의 IL 코드인데, 이 코드는 데이터 바인딩 시점에 실행되는 코드로서, 내 코드와 stack 연결이 없어 디버깅으로는 파악이 안됩니다.

(저 같이) 블레이저 내부 구조를 알지 못하면, IL 코드가 무엇을 의미하고, 왜 호출되었는 지 알기가 매우 어렵습니다.

예전에 비슷한 문제로 고생을 해서 조심하자 했는데, 이젠 새 대가리가 되었는 지 같은 실수를 반복한 것이죠 ㅠㅠ

어찌 되었건 이러한 예외 관련한 문제는 블레이저가 분명히 개선해야 할 부분으로 보여집니다.

2 Likes