I have a Flutter + Riverpod project in which I am fetching some data when a screen loads. Getting the Null check operator error but I am checking if the value is null or not beforehand. State has a nullable field currentlyReading
which is null at the beginning. Function to fetch data is being called in the constructor of the controller. The state is being updated correctly after fetching.
Trying to render UI conditionally based on the result of fetch but getting the error.
Controller that fetches data and manages state:
final bookControllerProvider = StateNotifierProvider<BookController, BookState>(
(ref) => BookController(ref.read(bookRepositoryProvider), ref));
class BookState {
final Book? currentlyReading;
final List<Book>? books;
final bool isLoading;
final String? error;
BookState(
{this.currentlyReading,
this.books = const [],
this.isLoading = true,
this.error});
BookState copyWith({
Book? currentlyReading,
List<Book>? books,
bool? isLoading,
String? error,
}) {
return BookState(
currentlyReading: currentlyReading ?? this.currentlyReading,
books: books ?? this.books,
isLoading: isLoading ?? this.isLoading,
error: error ?? this.error,
);
}
}
class BookController extends StateNotifier<BookState> {
final BookRepository _bookRepository;
final Ref _ref;
BookController(this._bookRepository, this._ref) : super(BookState()) {
getCurrentlyReading();
}
void getCurrentlyReading() async {
state = state.copyWith(isLoading: true);
final user = _ref.read(userProvider);
final book = await _bookRepository.getBook(user!.readingBook!);
book.fold((l) {
state = state.copyWith(error: l.message, isLoading: false);
}, (userBook) {
state = state.copyWith(currentlyReading: userBook, isLoading: false);
});
}
}
Using in UI:
final user = ref.watch(userProvider)!;
final bookData = ref.watch(bookControllerProvider);
return Scaffold(
body: SafeArea(
child: Padding(
padding:
const EdgeInsets.only(top: 16.0, right: 16, bottom: 8, left: 16),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 16),
Text(
'Currently Reading',
style: AppStyles.bodyText.copyWith(
fontSize: 18,
fontWeight: FontWeight.w500,
color: Pallete.textGrey),
),
const SizedBox(height: 16),
bookData.isLoading
? const Expanded(child: Center(child: Loader()))
: bookData.currentlyReading == null
? const Text('Some error occurred')
: BookInfo(
book: bookData.currentlyReading!, height: deviceHeight)
],
),
),
));
BookInfo:
class BookInfo extends StatelessWidget {
final Book book;
final double height;
const BookInfo({
Key? key,
required this.book,
required this.height,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Image(
image: NetworkImage(book.thumbnail!),
),
SizedBox(
height: height * 0.01,
),
Text(book.title,
style: AppStyles.subtext.copyWith(
color: Pallete.primaryBlue, fontWeight: FontWeight.w500)),
Text('by ${book.authors.join(', ')}', style: AppStyles.bodyText),
],
);
}
}
However, a simple Text
widget like below works when used in place of BookInfo
Text(bookData.currentlyReading!.title)
Your problem is not because of
bookData.currentlyReading
its happened inBookInfo
widget when try to buildImage
widget,book.thumbnail
may be null and you use!
on it: