void main(List<String> arguments) {
String myString = 'Hello world';
int myInteger = 5;
double myDouble = 5.5;
/*✅ int와 double은 num을 상속받고 있음. 될 수 있으면 사용하지 않도록..*/
num myNum = 5;
myNum = 5.5;
/*✅ dynamic 될 수 있으면 쓰지 말자*/
dynamic myAnything = 'Hello';
myAnything = 5;
myAnything = 5.5;
/*✅ 값을 바꾸기 싫을 때, final, 선언과 초기화를 동시에*/
final int myFinal = 10;
myFinal = 11;
/*✅ 선언과 초기화를 따로*/
int myDigit;
myDigit = 10;
/*✅ 타입이 명시 되지 않으면 type inferring*/
var inferType;
inferType = 100;
}
- 예를 들어, DB에 있는 사용자에 대한 정보를 가져올 때 id만 동일하면 동일한 사용자로 보고 싶을 때 우리는 어떻게 해야 할까?
- 하나의 객체에 연관되어 있는 여러가지의 프로퍼티들 중 특히 id만을 비교하도록 == operator를 구현해주면 될 것이다.
- 그런데 여러개를 해야 한다면? 아주 귀찮다. 그래서 이를 대신해주는 것이 Euqatable패키지이다.
// 1. Equatable를 extends 해준다.
// 2. Euqatable에 커서를 대고 cmd + .을 누르면 패키지를 import 할 수 있다.
// 3. Weather라는 class가 붉은 표시를 낼 것이고, 동일하게 cmd + .를 통해서 override 해준다.
// 4. 나머지 부분을 지우고, 동일한지 확인하고 싶은 부분을 리스트의 elements로 전달한다.
import 'package:equatable/equatable.dart';
import 'package:meta/meta.dart';
class Weather extends Equatable {
final String cityName;
final double temperatureCelsius;
final double temperatureFahrenheit;
Weather({
@required this.cityName,
@required this.temperatureCelsius,
this.temperatureFahrenheit,
});
@override
List<Object> get props => [
cityName,
temperatureCelsius,
temperatureFahrenheit,
];
}
3. 저장소 자세히 보기
- BLoC은 항상 Repository 레이어와 통신합니다. 통신 이후 새 데이터를 가져올지 아니면 로컬 캐시에서 가져올지를 결정하게 됩니다.
4. BLoC
- Events는 입력
- BLoC이 입력되는 Events에 따라 무엇을 할지 결정
- 그결과 State를 반환
- .yaml파일에 보면 이미 flutter_bloc dependencies가 설치되어 있는 것을 확인할 수 있음.(확실히 하길 원한다면 flutter pub get)
- lib에서 오른쪽 마우스 클릭 -> new bloc 선택 -> bloc명 생성 후 확인
5. Events
- WeatherEvent라는 Abstract class를 활용해 인터페이스 역할을 수행하게 한다.
- 각각의 Events는 WeatherEvent를 Extends하며, 해당 class가 초기화 되었을 때 데이터들을 fetching 할 수 있도록 내부에 usecase를 선언한다.
part of 'weather_bloc.dart';
abstract class WeatherEvent extends Equatable {
const WeatherEvent();
@override
List<Object> get props => [];
}
class GetWeather extends WeatherEvent {
final String cityName;
const GetWeather(this.cityName);
@override
List<Object> get props => [cityName];
}
class GetDetailedWeather extends WeatherEvent {
final String cityName;
const GetDetailedWeather(this.cityName);
@override
List<Object> get props => [cityName];
}
6. States
- BLoC은 함수처럼 값을 반환하는 방식이아니라 UI를 그리기 위해 필요한 모든 것들을 가지고 있는 States들을 가지고 있다.
- 또한 Events를 추가하거나, States를 청취하는 장소는 구분되어 있다.
- 얼마나 많은 States가 필요할까를 알기 위해 얼마나 다양한 UI가 필요할까?를 생각해 보면 된다.
1. 지역 검색
2. 로딩
3. 데이터 가져오기
4. Error 발생 알리기
class WeatherInitial extends WeatherState {
const WeatherInitial();
@override
List<Object> get props => [];
}
class WeatherLoading extends WeatherState {
const WeatherLoading();
@override
List<Object> get props => [];
}
class WeatherLoaded extends WeatherState {
final Weather weather;
const WeatherLoaded(this.weather);
@override
List<Object> get props => [weather];
}
class WeatherError extends WeatherState {
final String message;
const WeatherError(this.message);
@override
List<Object> get props => [message];
}
7. BLoC
- Event와 이에 따른 State를 정의 했다면 이를 연결(?)시키는 파이프 즉, BLoC를 정의할 필요가 있다.
- 특정 이벤트에 따라 우리가 원하는 State로 변환해주면 될일이다.
class WeatherBloc extends Bloc<WeatherEvent, WeatherState> {
final WeatherRepository repository;
WeatherBloc(this.repository);
@override
Stream<WeatherState> mapEventToState(
WeatherEvent event,
) async* {
yield WeatherLoading();
if (event is GetWeather) {
try {
final weather = await repository.fetchWeather(event.cityName);
yield WeatherLoaded(weather);
} on NetworkError {
yield WeatherError("Couldn't fetch weather. Is the device online?");
}
} else if (event is GetDetailedWeather) {
try {
final weather = await repository.fetchDetailedWeather(event.cityName);
yield WeatherLoaded(weather);
} on NetworkError {
yield WeatherError("Coulnd't fetch weather. Is the device online?");
}
}
}
@override
WeatherState get initialState => throw UnimplementedError();
}
8. BLoC 사용하기
- Widget들은 발생하는 events를 BLoC에 추가하고, BLoC이 반환하는 States에 따라 대응하고 UI를 다시 그리는 작업을 수행하게 된다.