首页 > 解决方案 > Flutter 和 Redux

问题描述

我写了一个使用 Redux 来管理我的状态的应用程序。我不知道为什么,但是当我启动我的应用程序时,我的控制台会抛出这种类型的错误:

The getter 'length' was called on null.
Receiver: null
Tried calling: length

我只是使用 redux 的初学者,所以如果这只是一个小而有趣的错误,请原谅:)

我粘贴下面的代码: order_screen.dart

class OrdersScreen extends StatelessWidget{
  void handleInitialBuild(OrdersScreenProps props){
    props.getOrders();
  }

  @override
  Widget build(BuildContext context){
    return StoreConnector<AppState, OrdersScreenProps>(
      converter: (store) => mapStateToProps(store),
      onInitialBuild: (props) => this.handleInitialBuild(props),
      builder: (context, props){
        List<Order> data = props.listResponse.data;
        bool loading = props.listResponse.loading;

        Widget body;
        if(loading){
          body = Center(
            child: CircularProgressIndicator(),
          );
        }else{
          body = ListView.separated(
            padding: const EdgeInsets.all(16.0),
            itemCount: data.length,
            separatorBuilder: (context, index) => Divider(),
            itemBuilder: (context, i) {
              Order order = data[i];

              return ListTile(
                title: Text(
                  order.title,
                ),
                onTap: () {
                  props.getOrderDetails(order.id);
                  Navigator.pushNamed(context, AppRoutes.orderDetails);
                },
              );
            },
          );
        }
        return Scaffold(
          appBar: AppBar(
            title: Text('Orders list'),
          ),
          body: body,
        );
      },
    );
  }
}

class OrdersScreenProps {
  final Function getOrders;
  final Function getOrderDetails;
  final ListOrdersState listResponse;

  OrdersScreenProps({
    this.getOrders,
    this.listResponse,
    this.getOrderDetails,
  });
}

OrdersScreenProps mapStateToProps(Store<AppState> store) {
  return OrdersScreenProps(
    listResponse: store.state.order.list,
    getOrders: () => store.dispatch(getOrders()),
    getOrderDetails: (int id) => store.dispatch(getOrderDetails(id)),
  );
}

order_actions.dart

const LIST_ORDERS_REQUEST = 'LIST_ORDERS_REQUEST';
const LIST_ORDERS_SUCCESS = 'LIST_ORDERS_SUCCESS';
const LIST_ORDERS_FAILURE = 'LIST_ORDERS_FAILURE';

RSAA getOrdersRequest(){
  return RSAA(
    method: 'GET',
    endpoint: 'http://10.0.2.2:80/order',
    types: [
      LIST_ORDERS_FAILURE,
      LIST_ORDERS_REQUEST,
      LIST_ORDERS_SUCCESS
    ],
    headers: {
      'Content-Type':'application/json',
    },
  );
}

ThunkAction<AppState> getOrders() => (Store<AppState> store) => store.dispatch(getOrdersRequest());

const GET_ORDERS_DETAILS_REQUEST = 'GET_ORDERS_DETAILS_REQUEST';
const GET_ORDERS_DETAILS_SUCCESS = 'GET_ORDERS_DETAILS_SUCCESS';
const GET_ORDERS_DETAILS_FAILURE = 'GET_ORDERS_DETAILS_FAILURE';

RSAA getOrderDetailsRequest(int id){
  return RSAA(
    method: 'GET',
    endpoint: 'http://10.0.2.2:80/order/$id',
    types: [
      GET_ORDERS_DETAILS_REQUEST,
      GET_ORDERS_DETAILS_SUCCESS,
      GET_ORDERS_DETAILS_FAILURE
    ],
    headers: {
      'Content-Type':'application-type',
    },
  );
}

ThunkAction<AppState> getOrderDetails(int id) => (Store<AppState> store) => store.dispatch(getOrderDetailsRequest(id));

order_state.dart

class OrderState{
  ListOrdersState list;
  OrderDetailsState details;

  OrderState({
    this.list,
    this.details,
  });

  factory OrderState.initial() => OrderState(
    list: ListOrdersState.initial(),
    details: OrderDetailsState.initial(),
  );
}

class ListOrdersState {
  dynamic error;
  bool loading;
  List<Order> data;

  ListOrdersState({
    this.error,
    this.loading,
    this.data,
  });

  factory ListOrdersState.initial() => ListOrdersState(
    error: null,
    loading: false,
    data: [],
  );
}

class OrderDetailsState {
  dynamic error;
  bool loading;
  OrderDetails data;

  OrderDetailsState({
    this.error,
    this.loading,
    this.data,
  });

  factory OrderDetailsState.initial() => OrderDetailsState(
    error: null,
    loading: false,
    data: null,
  );
}

app_state.dart

@immutable
class AppState {
  final UserState user;
  final OrderState order;

  AppState({
    this.user,
    this.order
  });

  factory AppState.initial() => AppState(
    user: UserState.initial(),
    order: OrderState.initial()
  );

  AppState copyWith({
    UserState user,
    OrderState order,
  }) {
    return AppState(
      user: user ?? this.user,
      order: order ?? this.order,
    );
  }

order_reducer.dart

OrderState orderResucer(OrderState state, FSA action){
  OrderState newState = state;

  switch (action.type) {
    case LIST_ORDERS_REQUEST:
      newState.list.error = null;
      newState.list.loading = true;
      newState.list.data = null;
      return newState;

    case LIST_ORDERS_SUCCESS:
      newState.list.error = null;
      newState.list.loading = false;
      newState.list.data = ordersFromJSONStr(action.payload);
      return newState;

    case LIST_ORDERS_FAILURE:
      newState.list.error = action.payload;
      newState.list.loading = false;
      newState.list.data = null;
      return newState;


    case GET_ORDERS_DETAILS_REQUEST:
      newState.details.error = null;
      newState.details.loading = true;
      newState.details.data = null;
      return newState;

    case GET_ORDERS_DETAILS_SUCCESS:
      newState.details.error = null;
      newState.details.loading = false;
      newState.details.data = orderFromJSONStr(action.payload);
      return newState;

    case GET_ORDERS_DETAILS_FAILURE:
      newState.details.error = action.payload;
      newState.details.loading = false;
      newState.details.data = null;
      return newState;

    default:
      return newState;
  }
}

List<Order> ordersFromJSONStr(dynamic payload) {
  Iterable jsonArray = json.decode(payload);
  return jsonArray.map((j) => Order.fromJSON(j)).toList();
}

OrderDetails orderFromJSONStr(dynamic payload) {
  return OrderDetails.fromJSON(json.decode(payload));
}

标签: flutterdartredux

解决方案


您需要做的第一件事是对减速器执行操作并调用相关操作以更改状态。

TypedReducer<OrderState, FSA>(orderReducer>); //pass it your reducers in store

触发相关动作

ThunkAction<AppState> getOrders() => (Store<AppState> store) ={
    store.dispatch(FSA(type: LIST_ORDERS_REQUEST);
    store.dispatch(getOrdersRequest().then((orders){
     store.dispatch(FSA(type: LIST_ORDERS_REQUEST);
}), onError(e){
     store.dispatch(FSA(type: LIST_ORDERS_FAILURE);
  }
};

您的 getOrders() 应该返回未来。创建 ThunkAction 的全部目的是返回一个函数,一旦其中的异步函数完成,该函数就会调度常规同步操作。


推荐阅读