brianegan / redux_thunk

Redux Middleware for handling functions as actions
MIT License
88 stars 8 forks source link

Improve Docs #5

Closed brianegan closed 5 years ago

brianegan commented 6 years ago

A few folks have asked for more documentation -- a perfectly reasonable request.

Lizhooh commented 6 years ago

+1, It is too far from the redux-thunk(js) structure. The example does not make people understand.

brianegan commented 6 years ago

@Lizhooh Could you describe what kind of docs or examples might help out? Also, could you describe a bit why you think it's too far from the original redux-thunk structure -- is it the library or the docs in this case?

Thanks!

Lizhooh commented 6 years ago

@brianegan Hi, I make the following suggestions.

This is the original words of the redux documentation.

Should return a new state in the reducer Actions must have a type property that indicates the type of action being performed.

So I think the example should be like this:

enum Types { Search }

final reducer = (String state, action) {
  switch (action['type']) {
    case Types.Search:
      return action['text'];
    default:
      return state;
  }
};

final action = (Store<String> store) async {
  final searchResults = await new Future.delayed(
    new Duration(seconds: 1),
    () => "Search Results",
  );

  store.dispatch({
    'type': Types.Search,
    'text': searchResults,
  });
};
brianegan commented 6 years ago

Thanks for the feedback!

In Dart, since we have Static Typing, I actually tend to avoid the "Flux Standard Action" pattern which uses a "type" parameter (often a String) and a "payload" of dynamic type. There are a few problems with this in Dart:

  1. Since Strings aren't unique, they can be accidentally duplicated.
  2. If you dispatch a Map, you lose type safety. For example, what if someone changes the map to deliver a 'payload' instead of 'text'? With static typing & proper classes, you can make that change safely and know you haven't broken anything.
  3. You need to check the type, then cast the type of payload. The Map in your example is a Map<String, dynamic>. Using is checks you can do both of these in 1 step.

I'd generally recommend using Static Typing rather than dynamic typing wherever you can, and something like this instead:

class SearchResultAction {
  final String result;

  SearchResultAction(this.result);
}

final reducer = (String state, action) {
  // Use the `is` Keyword to check the type of action. This will be type-safe, and it will cast the dynamic action to the proper type for ya!
  if (action is SearchResultAction) return action.result;

  return state;
};

final action = (Store<String> store) async {
  final searchResults = await new Future.delayed(
    new Duration(seconds: 1),
    () => "Search Results",
  );

  store.dispatch(SearchResultAction(searchResults));
};

That said, I can totally see why the example is too simple and I can definitely improve it. In my opinion, I think it makes sense to take advantage of the differences in Dart and make use of the advantages you get with static typing rather than thinking in JS terms and making everything a dynamic Map.

brianegan commented 5 years ago

More examples have been added, thanks to all the contributors!