[TIL] 20241120_ 기차 예매 앱 만들기(트러블슈팅)(수정!!)

ds-k.dev·2024년 11월 19일
0

TIL

목록 보기
21/26

문제

부모 위젯(seatList)의 상태를 자식 위젯(seatRow)에서 변경할 수 있도록 하게 하는 문제

고민과 적용

  1. 함수로 만들어서 UI를 그리자
  Widget seatRow(int idx, bool isSelected) {
  Widget seat = GestureDetector(
    onTap: () {
      // isSelected 상태를 변경할 로직을 작성하자
    },
    child: Container(
      margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
      width: 50,
      height: 50,
      decoration: BoxDecoration(
          color: isSelected ? Colors.purple : Colors.grey[300]!,
          borderRadius: BorderRadius.circular(8)),
    ),
  );
  return Row(
    children: [seat, seat, Text((idx + 1).toString()), seat, seat],
  );
}
  1. 그 UI를 List.generator를 이용해서 그리자
List.generate(20, (col) => seatRow())

여기까지는 아주 단순하게, 여러개의 seatUI를 그리면 되겠다고 생각했다.
하지만 좌석의 column과 row를 상태로 저장해야 되고, 그 상태를 변경하는 함수를 seatRow에 넣어야된다고 생각을 했다.
3. seatPage를 statefulWidget으로 변경

class SeatPage extends StatefulWidget {
  SeatPage({required this.departure, required this.arrival, super.key});

  final String departure;
  final String arrival;

  
  State<SeatPage> createState() => _SeatPageState();
}

class _SeatPageState extends State<SeatPage> {
  int? selectedCol;
  String? selectedRow;

  void onTapSeat(col, row) {
    setState(() {
      selectedCol = col;
      selectedRow = row;
    });
  }

homePage로부터 받는 변수는 daparture, arrival
seatPage에서 관리하는 상태 변수는 selectedCol과 selectedRow로 잡았고,
onTapSeat라는 상태변경 함수를 seatRow에 전달하려고 했다.

  1. 오류 발생
    1번에서 정의한 seatRow 함수에 onTapSeat를 변수로 전달하니 전달이 안되어서 한참 해맸다.
    검색해본 결과 자식 위젯에 부모 위젯의 상태를 변경하는 함수를 전달하려면, 자식 위젯도 statefulWidget으로 변경해줘야 하는 것을 알게 되었다.

결론 부분을 보면 알겠지만 이 검색결과는 틀렸다. widget으로만 전달하면 문제가 없다.

  1. 해결
import 'package:flutter/material.dart';

class seatRow extends StatefulWidget {
  seatRow(
      {required this.col,
      required this.onTapSeat,
      this.selectedCol,
      this.selectedRow,
      super.key});

  final int col;

  int? selectedCol;
  String? selectedRow;
  Function onTapSeat;

  
  State<seatRow> createState() => _seatRowState();
}

class _seatRowState extends State<seatRow> {
  Widget seat(String row) {
    return GestureDetector(
      onTap: () {
        // 상태 변화를 시킬수 있는 함수
        widget.onTapSeat(widget.col + 1, row);
      },
      child: Container(
        margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
        width: 50,
        height: 50,
        decoration: BoxDecoration(
            color: row == widget.selectedRow &&
                    widget.col + 1 == widget.selectedCol
                ? Colors.purple
                : Colors.grey[300]!,
            borderRadius: BorderRadius.circular(8)),
      ),
    );
  }

  
  Widget build(Object context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        seat("A"),
        seat("B"),
        Container(
            margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
            width: 50,
            height: 50,
            alignment: Alignment.center,
            child: Text((widget.col + 1).toString())),
        seat("C"),
        seat("D")
      ],
    );
  }
}

결과라기 보다는 수정

위와 같이 결론을 내리려고 하는데, state를 갖고 있는 위젯은 부모 위젯이고, 자식 위젯은 그것을 변경하기만 하는 것 뿐인데, 왜 자식 위젯이 statefulWidget이여야 되는 것인지 이해가 가지 않았다.
그래서 해당 위젯을 다시 statelessWidget으로 변경을 해주었는데...

import 'package:flutter/material.dart';

class SeatRow extends StatelessWidget {
  SeatRow(
      {required this.col,
      required this.onTapSeat,
      this.selectedCol,
      this.selectedRow,
      super.key});

  final int col;

  int? selectedCol;
  String? selectedRow;
  Function onTapSeat;

  Widget seat(String row) {
    return GestureDetector(
      onTap: () {
        // 상태 변화를 시킬수 있는 함수
        onTapSeat(col + 1, row);
      },
      child: Container(
        margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
        width: 50,
        height: 50,
        decoration: BoxDecoration(
            color: row == selectedRow && col + 1 == selectedCol
                ? Colors.purple
                : Colors.grey[300]!,
            borderRadius: BorderRadius.circular(8)),
      ),
    );
  }

  
  Widget build(Object context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        seat("A"),
        seat("B"),
        Container(
            margin: EdgeInsets.symmetric(vertical: 4.0, horizontal: 2.0),
            width: 50,
            height: 50,
            alignment: Alignment.center,
            child: Text((col + 1).toString())),
        seat("C"),
        seat("D")
      ],
    );
  }
}

멀쩡하게 동작한다.

심플하게 state가 존재하는 위젯에서만 statefulWidget을 사용한다고 기억하면 될 것 같다.

아니였다.. 함수로 해도 전혀 문제가 없었다..! 내가 잘못 썼나보다

0개의 댓글