분류, 패키지 및 저장소 검색

패키지 상세v8.0.0

provider_for_redux

Provider와 Redux를 함께 사용할 수 있게 해줍니다. 브로일러플레이트가 없는 Redux 버전인 AsyncRedux(https://pub.dev/packages/async_redux)를 사용합니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
118
좋아요
16
Pub 점수
150

패키지 설치

flutter pub add provider_for_redux

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

provider_for_redux 는 경량이고 빌러플레이트가 없는 Redux 구현인 AsyncRedux 를 사용하여 Provider 와 Redux 간의 원활한 통합을 가능하게 합니다. 개발자들은 의존성 주입을 위해 Provider 의 단순함을 활용하면서도 Redux 의 예측 가능한 상태 관리의 이점을 누릴 수 있습니다. 이 패키지는 과도한 코드 없이 구조화된 상태 처리가 필요한 앱에 이상적입니다. 모든 주요 플랫폼을 지원하며 비동기 작업과 불변 상태 패턴을 통해 상태 업데이트를 간소화합니다.

사용 사례

  • 확장 가능한 상태 관리를 위한 Provider와 Redux의 결합
  • 예측 가능한 상태 흐름으로 대규모 플러터 앱 만들기
  • 복잡한 애플리케이션에서 상태 로직 간소화
  • Provider의 반응형 위젯과 함께 AsyncRedux 사용하기
  • 기존의 Redux 로직을 더 깔끔한 패턴으로 이전하기

주요 기능

  • Provider를 AsyncRedux와 통합합니다
  • 전통적인 Redux에 비해 반복 코드를 줄입니다
  • 비동기 상태 업데이트를 지원합니다
  • 형 안전한 상태 및 액션 처리를 제공
  • 모든 플러터 플랫폼에서 작동합니다

적합한 대상

  • Redux에 익숙한 개발자
  • 구조화된 상태 관리가 필요한 팀
  • 의존성 주입과 상태 제어를 모두 필요로 하는 프로젝트
  • 복잡한 상태 로직을 가진 앱
  • Redux 봐일플레이트를 피하고 싶은 사람

고려 사항

  • Provider 및 Redux 개념에 대한 이해가 필요합니다
  • 작은 앱에 복잡성을 추가할 수 있습니다
  • AsyncRedux에 의존하며, 이는 자체 학습 곡선을 가지고 있다
  • 간단한 상태 요구 사항에 적합하지 않습니다
  • 중소에서 대규모 프로젝트에 가장 적합

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

pub package

provider_for_redux

With Provider you can inject your state, but it's your job to figure out how to update that state, structure the solution etc. In other words, Provider is a great alternative to InheritedWidget, and lets you do dependency injection, but you still need to do your own state management.

What people mean by “Provider as state management” is usually using Provider to do scoped model. But as a matter of fact, this is not the only possible architecture using Provider. You can use it with Bloc, Mobx, Redux and other.

This package lets you use it with AsyncRedux, the non-boilerplate version of Redux.

How to use it

Please, read the async_redux documentation first, if you haven't already.

You should have learned that to use AsyncRedux the traditional way, you provide the Redux store to your app by wrapping it with a StoreProvider, and then using the so called "connector" widgets, like the MyHomePageConnector below:

@override
Widget build(BuildContext context) =>
    StoreProvider<AppState>(
        store: store,
        child: MaterialApp(
          home: MyHomePageConnector(),
        ));

Now, if you want to use AsyncRedux with Provider, simply remove the StoreProvider and use AsyncReduxProvider instead. Also, you won't need the connector widgets anymore, since you will use Provider instead.

For example:

@override
Widget build(BuildContext context) =>
    AsyncReduxProvider<AppState>.value( // Instead of StoreProvider.
        value: store,
        child: MaterialApp(
          home: MyHomePage(), // Instead of MyHomePageConnector. 
        ));

The AsyncReduxProvider widget above will expose the store, the state, and the dispatch method to its descendants:

  • The Redux store, of type Store. Get it like this: Provider.of<Store<AppState>>(context).

  • The store's state, of type AppState. Get it like this: Provider.of<AppState>(context).

  • The dispatch method, of type Dispatch. Get it like this: Provider.of<Dispatch>(context).

This is a complete example:

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  int counter(context) =>
      Provider
          .of<AppState>(context)
          .counter;

  String description(context) =>
      Provider
          .of<AppState>(context)
          .description;

  VoidCallback onIncrement(context) =>
          () => Provider.of<Dispatch>(context, listen: false)(IncrementAndGetDescriptionAction());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Increment Example')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("You've pushed the button:"),
            Text('${counter(context)}', style: TextStyle(fontSize: 30)),
            Text('${description(context)}', style: TextStyle(fontSize: 15)),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: onIncrement(context),
        child: Icon(Icons.add),
      ),
    );
  }
}

Try running the Provider.of example.

Consumer

You can use Provider's Consumer class to read from the store. For example:

return Consumer<Store<AppState>>(
   builder: (context, store, child) =>
      ...
      Text('${store.state.counter}'),
      ...
      onPressed: () => store.dispatch(IncrementAction()),
),

But it's easier if you use ReduxConsumer, which already gives you the store, the state, and the dispatch method:

return ReduxConsumer<AppState>(
   builder: (context, store, state, dispatch, child) => ...

This is a complete example:

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ReduxConsumer<AppState>(
      builder: (context, store, state, dispatch, child) => Scaffold(
        appBar: AppBar(title: Text('Increment Example')),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text("You've pushed the button:"),
              Text('${state.counter}', style: TextStyle(fontSize: 30)),
              Text('${state.description}', style: TextStyle(fontSize: 15)),
            ],
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => dispatch(IncrementAndGetDescriptionAction()),
          child: Icon(Icons.add),
        ),
      ),
    );
  }
}

Try running the ReduxConsumer example.

Selector

You can use Provider's Selector class to read from the store, while preventing unnecessary widget rebuilds. For example:

return Selector<Store<AppState>, Tuple2<int, Dispatch>>(

   selector: (context, store) => 
      Tuple2(store.state.counter, store.dispatch),

   builder: (context, model, child) => 
      ...     
      Text('${model.item1}'),
      ...
      onPressed: () => model.item3(IncrementAction()),      
      ),

Your selector parameter must return a "model" which you can use to build your widget in the builder parameter. In the above example the model is a Tuple2 instance, but you can return any immutable object that correctly implements equals and hashcode. The widget will rebuild whenever the model changes.

But it's easier if you use ReduxSelector, which already gives you the store, the state, and the dispatch method:

return ReduxSelector<AppState, Tuple2<int, String>>(
selector: (context, state) => Tuple2(state.counter, store.dispatch),
builder: (ctx, store, state, dispatch, model, child) =>
   ...
   Text('${state.counter}'),
   ...
   onPressed: () => store.dispatch(IncrementAction()
   ),
),

Try running the ReduxSelector with model example.

However, ReduxSelector also lets you return a List as the model. In case you do that, it will rebuild the widget whenever any of the items in the list changes:

return ReduxSelector<AppState, dynamic>(
selector: (context, state) => [...],
builder: (context, store, state, dispatch, model, child) => ...    

Using ReduxSelector with a list is the easiest way of all, since you just need to list all of the state parts that should trigger a rebuild.

Note: The builder gives you both the state and the model, and you can choose one of them to build your widget from. While using state is probably easier for you, it's also easier to accidentally use something you forget to add to the model, and then wonder why the Widget doesn't rebuild. So you have two options:

  1. Use only the model and have the compiler make sure there's no state you're using from outside of the model.
  2. Use state directly, and have yourself the responsibility to make you've listed everything you' re using in the model.

This is a complete example:


Widget build(BuildContext context) {       
  return ReduxSelector<AppState, dynamic>(
     
      selector: (context, state) => [
                                    state.counter, 
                                    state.description
                                    ],

      builder: (context, store, state, dispatch, model, child) => 
         Scaffold(
             appBar: AppBar(title: Text('Increment Example')),
             body: Center(
               child: Column(
                 mainAxisAlignment: MainAxisAlignment.center,
                 children: [
                   Text("You've pushed the button:"),
                   Text('${state.counter}', style: TextStyle(fontSize: 30)),
                   Text('${state.description}', style: TextStyle(fontSize: 15)),
                 ],
               ),
             ),
             floatingActionButton: FloatingActionButton(
               onPressed: () => dispatch(IncrementAndGetDescriptionAction()),
               child: Icon(Icons.add),
             )));
}

Try running the ReduxSelector with list example.

Migrating

When you use AsyncReduxProvider you will notice that both Provider and AsyncRedux's StoreConnector will work simultaneously. You can mix and match both of them, as desired, or slowly migrate between them.


By Marcelo Glasberg

glasberg.dev
github.com/marcglasberg
linkedin.com/in/marcglasberg/
twitter.com/glasbergmarcelo
stackoverflow.com/users/3411681/marcg
medium.com/@marcglasberg

My article in the official Flutter documentation:

The Flutter packages I've authored:

My Medium Articles:

카테고리

의존성

의존성 목록 3 개

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.