【问题标题】:Where to put chained actions in React/Redux在 React/Redux 中将链式操作放在哪里
【发布时间】:2018-01-24 00:00:44
【问题描述】:

相当简单的用例:我有会导致执行 ajax 请求然后更新列表的操作/事件。

问题是我不确定如何(具体来说,在哪里在页面更改时启动对新列表的请求。

redux 商店

const defaultStore = {
  list: [],
  page: 1    
};

包装组件

const wrapper = props => (
  <div>
    <List {...props}> {/* This list should have page controls */}
      <PageControls {...props} />
    </List>
    <List /> {/* This list should not have page controls */}
  </div>
);

列表组件

const List = props => (
  <div>
    {props.children} {/* render page controls if present */}
    {props.items.map((item, k) => <div key={k}>item</div>
  </div>
);

分页控件组件

const PageControls = props => (
  <div>
    <span onClick={props.changePage(-1)}>Backward</span>
    <span onClick={props.changePage(1)}>Forward</span>
  </div>
);

动作创造者

function changePage(delta) {
  return {
    type: 'CHANGE_PAGE',
    delta
  };
}

// utilizes react-thunk middleware
function getList(page = 1) {
  return dispatch => 
    axios.get(`/path/to/api?page=${page}`)
      .then(res => dispatch(updateList(res.data));
}

function updateList(newList) {
  return { 
    type: 'UPDATE_LIST',
    newList
  };
}

减速器

function reducer(state = {}, action) {
  switch(action.type) {
    case 'CHANGE_PAGE':
      return {...state, page: state.page + action.delta};
    case 'UPDATE_LIST':
      return {...state, list: action.newList};
    default:
      return state;
  }
}

此时我可以做几件事——我可以让每个应该触发列表更新的 actionCreator 调度该操作:

function changePage(delta) {
  return dispatch => {
    dispatch({
      type: 'CHANGE_PAGE',
      delta
    });

    return dispatch(getList(store.getState() + delta));
  }
}

但这似乎很混乱。现在,我不仅要获取我的store,而且还必须将影响列表的每个 actionCreator 变成一个 thunk。

我唯一能想到的另一件事是让我的&lt;List&gt; 组件在某处使用store.subscribe 来观察页面的变化,然后启动另一个getList 操作,但这似乎也像我正在移动了解什么会触发和不会触发从 Redux 到我的 React 组件的状态更改。

有什么想法吗?

【问题讨论】:

    标签: reactjs redux flux


    【解决方案1】:

    好吧,也许你应该改变你的方法。我没有理由为更改页面和检索列表进行两项操作。您可以在按钮单击时发送getPage() 操作,传递下一页编号。这应该检索项目列表并刷新您的页面。

    在您的商店中,您应该跟踪当前页面,因此每次页面刷新时,getPage() 参数的值也会更新。

    例如(假设当前页面不是从 API 中检索到的):

    function getPage(page = 1) {
      return dispatch => 
        axios.get(`/path/to/api?page=${page}`)
          .then(res => dispatch(updatePage(res.data, page));
    }
    
    function updatePage(newList, currentPage) {
      return { 
        type: 'UPDATE_PAGE',
        newList,
        currentPage,
      };
    }
    

    并将所需的组件连接到商店,在您的情况下,它将是 ListPageControls 组件。

    const PageControls = props => (
      <div>
        <span onClick={props.getPage(props.currentPage - 1)}>Backward</span>
        <span onClick={props.getPage(props.currentPage + 1)}>Forward</span>
      </div>
    );
    

    这将允许您维护简单和干净的代码。您也可以从多个不相关的组件触发它。

    【讨论】:

    • 这行得通,谢谢。我唯一的问题是,这就是 redux 的使用方式吗?我本质上是在调用一个执行异步然后调度一个动作的函数。这似乎与在组件中执行异步调用没有太大区别。我认为 Redux 中的想法是状态响应操作提交,而不是在获取状态后分派操作提交。
    • 是的。 redux 的想法是让应用程序中的每个组件都可以使用全局存储。它也适用于 redux 操作。当然,有多种方法可以获取数据,然后调度 redux 操作,但是将其保存在一个与组件无关的单一位置始终是最好的主意。通过这种方式,您可以使您的应用程序在未来更具可扩展性。组件应该尽可能简单,并且它应该只呈现数据或接受输入,没有后台逻辑。您还可以阅读有关 redux-saga 的信息。使用生成器更高级地使用 redux。
    猜你喜欢
    • 2017-03-08
    • 2018-11-10
    • 2017-11-03
    • 1970-01-01
    • 2018-06-19
    • 2018-07-14
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    相关资源
    最近更新 更多