Flutter로 어플로 만들 때 변수 값 변경이 왜 필요할까요? 변수 값 변경이 불가능한 경우, 변수의 양은 기하급수적으로 늘어나고, 일일이 변수 코드를 작성해야 하기 때문입니다. 이번 글에서 변수 값 변경하는 방법에 대해 자세히 알아보겠습니다.
가장 기본: 재할당으로 바꾸기
한 번 선언한 변수는 이후에 var를 다시 쓰지 않고, 변수명에 새 값을 대입해 바꿉니다.
var x = 1; // 선언 + 초기값 x = 2; // 값 변경(재할당) x = 3; // 값 변경(재할당)
첫 줄에서 x라는 변수를 만들고 1을 넣습니다. 그 다음 줄들은 x에 들어있는 값을 각각 2, 3으로 덮어쓰기합니다. var는 처음 선언할 때만 쓰고, 이후에는 x = ...만 쓰면 됩니다.
var x = 1; x = 2; // OK x = "a"; // 오류: int 변수에 String 대입 불가
var x = 1;에서 초기값이 정수이므로 x는 int로 확정됩니다. 그래서 이후에는 int만 넣을 수 있습니다. 타입이 다른 "a"를 넣으면 컴파일 오류가 납니다.
기존 값을 이용해서 바꾸기
값을 “교체”하는 것뿐 아니라, 현재 값에 기반해서 새 값을 계산해 넣는 방식도 매우 흔합니다.
var count = 0; count = count + 1; // 1 증가 count = count - 1; // 1 감소
count = count + 1;은 “현재 count 값에 1을 더한 결과를 다시 count에 넣어라”라는 뜻입니다. 즉, 현재 값 기반으로 새 값을 계산한 뒤 다시 대입하는 패턴입니다.
var count = 0; count += 1; // count = count + 1 count -= 2; // count = count - 2
실무에서는 축약 연산도 자주 씁니다. +=는 “더해서 다시 넣기”, -=는 “빼서 다시 넣기”를 짧게 쓴 표현입니다.
조건에 따라 바꾸기 (if / switch)
어떤 상황에서는 “조건이 맞을 때만” 변수값이 바뀌어야 합니다. 이때 조건문을 사용합니다.
var score = 50;
if (score < 60) {
score = 60; // 합격 처리
}
score < 60이 참일 때만 중괄호 안이 실행됩니다. 즉 점수가 60 미만이면 강제로 60으로 바꾸고, 60 이상이면 아무 일도 일어나지 않아 값이 유지됩니다.
반복하면서 바꾸기 (for / while)
반복문 안에서 재할당하면 “여러 번” 값이 바뀝니다. 합계, 카운트, 상태 갱신에 자주 사용됩니다.
var sum = 0;
for (var i = 1; i <= 5; i++) {
sum = sum + i; // 반복마다 값이 바뀜
}
// sum == 15
i가 1부터 5까지 변하는 동안, 매번 sum에 i를 더한 값을 다시 sum에 넣습니다. 결과적으로 sum은 1+2+3+4+5가 누적되어 15가 됩니다.
함수 결과로 바꾸기 (계산/가공한 값을 넣기)
값을 직접 쓰지 않고, 함수가 반환한 결과로 변수를 바꾸는 패턴입니다.
int discount(int price) {
return (price * 0.9).toInt();
}
var price = 10000;
price = discount(price); // 9000으로 변경
discount(price)는 할인된 금액을 계산해 반환합니다. price = discount(price);는 “할인 계산 결과를 다시 price에 넣어서 가격을 갱신하라”라는 의미입니다. 즉, 함수의 결과로 변수값을 업데이트합니다.
비동기 결과로 바꾸기 (await / Future)
네트워크 요청, DB 조회처럼 “나중에 결과가 도착”하는 작업은 await 결과로 값을 바꿉니다.
Future<int> fetchCount() async {
await Future.delayed(const Duration(seconds: 1));
return 10;
}
var count = 0;
Future<void> load() async {
count = await fetchCount(); // 나중에 10으로 변경
}
fetchCount()는 1초 뒤에 10을 반환한다고 가정한 함수입니다. await fetchCount()는 “결과가 올 때까지 기다린 뒤 그 결과를 받는다”는 뜻이고, 그 결과를 count에 대입하므로 시간이 지난 뒤에 count가 바뀝니다.
이벤트가 발생했을 때 바꾸기 (버튼/입력 등)
Flutter에서는 사용자의 행동(클릭/입력/탭 등)이 변수값을 바꾸는 가장 대표적인 트리거입니다.
var count = 0;
void onPressed() {
count = count + 1; // 버튼 클릭 시 값 변경
}
onPressed()는 보통 “버튼이 눌렸을 때 호출되는 함수”입니다. 즉, 사용자가 버튼을 눌렀을 때만 실행되고 그때 count가 1 증가합니다. 이벤트가 없으면 함수도 실행되지 않으니 값도 바뀌지 않습니다.
실패했을 때 다른 값으로 바꾸기 (try/catch)
실패 가능성이 있는 로직이라면, 실패했을 때 “대체값”으로 바꾸는 방식이 실전에서 많이 쓰입니다.
var result = 0;
try {
// 실패할 수 있는 로직
throw Exception("fail");
} catch (e) {
result = -1; // 실패 시 대체값으로 변경
}
try 블록에서 예외가 발생하면 catch로 넘어갑니다. 이 예시는 강제로 예외를 발생시키고 있으므로 catch가 실행되어 result를 -1로 바꿉니다. 즉, 실패 시 대체값으로 변수값을 갱신하는 패턴입니다.
재할당 없이도 “바뀌는 것처럼 보이는” 경우
변수에 새 값을 대입하지 않았는데도 값이 바뀐 것처럼 느껴질 때가 있습니다.
그건 보통 변수 자체가 아니라, 변수가 가리키는 객체 내부가 변경된 경우입니다.
var list = [1, 2]; list.add(3); // list에 재할당은 없지만, 내부 요소가 추가됨
이 코드는 list = ...처럼 재할당을 하지 않습니다. 대신 list가 가리키는 리스트 객체의 내부에 3을 추가합니다. 즉 “변수에 새 값을 넣은 것”이 아니라 객체 내부 상태가 변경된 것입니다. 초보자 입장에서는 “값이 바뀐 것처럼” 보이기 때문에 재할당과 구분이 필요합니다.
변수 변경 못하는 함수 (final / const)
변수값을 바꾸려면 기본적으로 재할당이 가능해야 합니다. final과 const는 재할당이 금지됩니다.
final x = 1; x = 2; // 오류: final은 한 번만 대입 가능
final은 “한 번만 값 대입 가능”이라서 두 번째 대입(재할당)이 금지됩니다.
const y = 1; y = 2; // 오류: const는 컴파일 타임 상수
const는 컴파일 시점에 확정되는 상수라 재할당이 불가능합니다.
결론
Flutter 앱은 실행 중에 화면과 상태가 계속 변합니다. 버튼을 누르면 숫자가 올라가고, 입력값이 바뀌면 UI가 갱신되며, 서버 응답이 오면 데이터가 업데이트됩니다. 이 변화를 표현하는 가장 기본적인 수단이 “변수값 변경(대입/재할당)”입니다. 변수값을 바꿀 수 없다면 동일한 목적을 위해 매번 새로운 변수를 추가로 만들어야 하고, 그만큼 코드가 복잡해지며 유지보수가 어려워집니다. 따라서 Dart에서 재할당, 조건/반복 기반 변경, 함수/비동기 결과 반영, 이벤트 처리, 예외 시 대체값 설정, 객체 내부 변경과 재할당의 구분까지 이해해두면 Flutter에서 상태 관리와 UI 업데이트 흐름을 훨씬 안정적으로 설계할 수 있습니다.
FAQ
var로 선언한 변수는 언제든지 마음대로 바꿀 수 있나요?
var 자체가 “마음대로 바꾼다”는 의미는 아니고, “처음 값으로 타입을 추론한다”는 의미입니다. 한 번 타입이 정해지면 같은 타입의 값으로는 재할당이 가능하지만, 다른 타입으로는 바꿀 수 없습니다.
var는 왜 한 번만 쓰고 그 다음엔 안 쓰나요?
var는 “변수를 선언할 때” 사용하는 키워드입니다. 선언은 한 번만 하면 충분하고, 이후에는 이미 존재하는 변수에 새 값을 대입하는 단계이므로 x = ...처럼 변수명만 사용합니다.
값이 바뀌는 건 무조건 if나 for 같은 조건이 있어야 하나요?
반드시 조건문이나 반복문이 있어야 하는 것은 아닙니다. 값 변경은 “대입 코드가 실행될 때” 일어나며, 그 실행 계기는 조건/반복뿐 아니라 함수 호출, 사용자 이벤트, 비동기 응답, 타이머, 스트림 이벤트 등 다양합니다.
리스트에 add를 했는데 재할당이 아닌데도 값이 바뀌는 건 왜 그런가요?
그 경우는 변수에 새 값을 넣은 것이 아니라, 변수가 가리키는 객체(리스트) 내부가 변경된 것입니다. 재할당은 list = ...처럼 참조 자체를 교체하는 것이고, list.add(...)는 같은 리스트 객체의 내용만 바꾸는 “객체 내부 변경”입니다.
final은 “나중에 결정된다”면서 왜 값을 바꾸면 오류가 나나요?
final은 “한 번만 대입 가능”이라는 규칙을 가집니다. 사용자의 입력이나 서버 응답처럼 나중에 값이 정해지는 것은 가능하지만, 정해진 뒤에는 다시 다른 값으로 재할당할 수 없습니다. 즉 “지연 결정”과 “재할당 가능”은 다른 개념입니다.
const는 언제 써야 하고 왜 더 엄격한가요?
const는 컴파일 시점에 값이 확정되는 상수입니다. 실행 중에 변할 가능성이 조금이라도 있으면 const를 쓸 수 없습니다. 변하지 않는 고정 값(예: 고정 문자열, 고정 숫자, 고정 설정값)처럼 진짜 상수에 사용합니다.
비동기 작업(await)에서 값 변경은 어떤 점을 주의해야 하나요?
await는 결과가 “나중에” 도착하기 때문에, 값이 즉시 바뀌지 않고 특정 시점 이후에 바뀝니다. Flutter에서는 이 변경을 화면에 반영하려면 상태 갱신 타이밍을 맞춰야 하며, 상태 관리 방식(setState, Provider, Riverpod 등)에 따라 반영 방법이 달라질 수 있습니다.
변수값을 바꾸는 것과 UI가 바뀌는 것은 같은 건가요?
같지 않습니다. 변수값 변경은 데이터가 바뀐 것이고, UI 변경은 그 데이터를 화면에 다시 그린 결과입니다. Flutter에서는 상태가 바뀌었을 때 화면을 다시 빌드하도록 연결하는 과정이 필요하며, 그 연결이 없으면 값이 바뀌어도 화면이 그대로일 수 있습니다.