사례: Flutter가 위젯 재구축을 최적화하는 방법과 전화번호를 otp로 사용한 이유

11106 단어 fluttertodayilearned
나는 돈이 거의 없는 사람이고 훨씬 더 적은 코드 줄의 개발자입니다.

이건 내 버튼이야

class CustomButton extends StatelessWidget {
  const CustomButton({Key? key, required this.title, required this.onTap})
      : super(key: key);

  final String title;
  final VoidCallback onTap;

  @override
  Widget build(BuildContext context) {
    return TextButton(
      onPressed: onTap,
      child: Text(
        title,
      ),
    );
  }
}


이것은 내 텍스트 필드입니다.

class CustomTextField extends StatelessWidget {
  CustomTextField(
      {Key? key,
      required this.hintText,
      this.fillColor = Colors.grey})
      : super(key: key);

  final String hintText;
  final Color fillColor;

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 32),
      child: TextFormField(
        decoration: InputDecoration(
            hintText: hintText, fillColor: fillColor, filled: true),
      ),
    );
  }
}


... 그리고 이것은 아방가르드 보안이 적용된 로그인 화면입니다.

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool showotp = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        mainAxisSize: MainAxisSize.max,
        children: [
          !showotp
              ? CustomTextField(
                  hintText: 'Phone number',
                )
              : CustomTextField(
                  hintText: 'OTP',
                ),
          !showotp
              ? CustomButton(
                  onTap: () => setState(
                    () {
                      showotp = true;
                    },
                  ),
                  title: 'Send OTP',
                )
              : CustomButton(
                  onTap: () => ScaffoldMessenger.of(context).showSnackBar(
                      const SnackBar(content: Text('OTP Submitted'))),
                  title: 'Verify OTP',
                )
        ],
      ),
    );
  }
}


괜찮은 것 같죠? 이 보석 같은 코드를 살펴보면 작동 방식에 대한 대략적인 아이디어를 얻을 수 있습니다. 이것dartpad.dev snippet에서 회전을 위해 꺼낼 수 있습니다.

문제가 있습니다.



인식하지 못한 경우 돌아가서 이 단계를 다시 시도하십시오. 전화번호를 입력하고 send otp를 누르면 텍스트 필드가 변경되는 동안 해당 필드에 전화번호가 미리 채워집니다. 미리 채워진 숫자를 지우면 otp 힌트 텍스트를 볼 수 있습니다. 그런데 왜 이런 행동이 일어나는 걸까요?

Flutter의 Sublinear 위젯 트리 구축 시작

하위 선형 위젯 구축



Flutter에 대한 일반적인 격언은 "모든 것이 위젯입니다"입니다. 예를 들어 Padding은 위젯의 속성이 아니라 위젯 자체입니다. 결과적으로 Flutter는 깊게 중첩된 위젯 트리를 처리해야 합니다. 이 전체 트리를 일반적인 방법으로 탐색하면 성능이 저하되므로 Flutter는 하위 선형 시간에 이를 달성하기 위해 약간의 트릭을 사용합니다.

이러한 속임수 중 하나는 자식이 자신을 더티(상태 변경)로 표시하지 않은 경우 트리를 방문하지 않는 것입니다. 이 트리는 또한 위젯의 상태를 보유합니다. 이제 더티 위젯을 찾기 위해 트리 diff 알고리즘이 더 쉬울 수 있지만 반드시 효율적이지는 않으므로 Flutter는 O(N) 복잡성의 자체 알고리즘을 사용합니다. 찾을 수 있는 대부분의 레이아웃 알고리즘은 O(n^2) 이하이며 Flutter에서 60fps 렌더링을 달성하려면 하위 선형 알고리즘이 핵심입니다.

The child list reconciliation algorithm optimizes for the following cases:

  • The old child list is empty.
  • The two lists are identical.
  • There is an insertion or removal of one or more widgets in exactly one place in the list.
  • If each list contains a widget with the same key, the two widgets are matched.
  • Along with keys, the runtime type is also checked at the same level.


제 경우 런타임 타입은 동일했고, 위젯에 할당된 키가 없었기 때문에 같은 상태를 가진 것으로 간주했습니다. 따라서 간단한 부울 플래그 때문에 위젯이 전환되는 동안 해당 위젯의 상태는 전환되지 않습니다. 그리하여 이전 위젯의 상태가 새 위젯에 부과됩니다. 불쌍한 것은 하나를 다른 것과 구별할 수 없기 때문입니다 :(

쉬운 해결책은 각 텍스트 필드에 고유한 키를 전달하는 것입니다!

처음에 이것이 나에게 버그처럼 느껴졌던 이유는 우리가 인스턴스에 따라 그리고 때때로 보유하고 있는 데이터에 따라 동일한 런타임 유형의 다른 개체를 구별하는 데 익숙하기 때문입니다. Flutter가 왜 그런 일을 하는지 이해하고 나면 상황이 더 명확해집니다. 그렇죠?



혹시 제가 놓친 부분이 더 있다면 댓글로 알려주세요!

좋은 웹페이지 즐겨찾기