【问题标题】:React redux separation of concernsReact redux 关注点分离
【发布时间】:2016-05-30 23:38:40
【问题描述】:

我正在尝试构建一个简单的应用程序来查看从 nasa 的每日图片服务​​ (https://api.nasa.gov/api.html#apod) 发布的照片​​。当前正在监视按键,然后根据按键是向左、向上、向右或向下的箭头来更改日期(以及异步图片)。这些将相应地更改由一周或一天表示的日期(想象一下在日历上一次移动一个正方形)。

我遇到的问题是:我创建了一个异步操作创建器来获取下一个潜在日期 - 但是我需要知道应用程序的当前状态以及检索新日期的按键。有没有办法将其封装到动作创建者中?或者我应该将应用程序状态放在应用程序中调用导出的动作创建者的位置,这样我就可以让我的动作创建者不知道应用程序的状态?我尝试通过在componentDidMount 中为顶级Component 绑定keydown 函数来做到这一点,但是绑定到应用程序商店似乎并没有反映reducer 中发生的更改。

依赖redux-thunk中间件和q的异步逻辑:

// This function needs to know the current state of the application
// I don't seem to be able to pass in a valid representation of the current state
function goGetAPIUrl(date) {
   ...
}

function getAsync(date) {
  return function (dispatch) {
    return goGetAPIUrl(date).then(
      val => dispatch(gotURL(val)),
      error => dispatch(apologize(error))
    );
  };
}

export default function eventuallyGetAsync(event, date) {
  if(event.which == 37...) {
    return getAsync(date);
  } else {
    return {
      type: "NOACTION"
    }
  }
}

这是到 gridAppState 的顶级绑定,以及在顶级发生的其他可能相关但我不太了解的内容。

class App extends React.Component {
  componentDidMount() {
    const { gridAppState, actions } = this.props;
    document.addEventListener("keydown", function() {
      actions.eventuallyGetAsync(event, gridAppState.date);
    });
  }
  render() {
    const { gridAppState, actions } = this.props;
    return (
        <GridApp gridAppState={gridAppState} actions={actions} />
    );
  }
}

App.propTypes = {
  actions: PropTypes.object.isRequired,
  gridAppState: PropTypes.object.isRequired
};

function mapStateToProps(state) {
  return {
    gridAppState: state.gridAppState
  };
}

function mapDispatchToProps(dispatch) {
  return {
    actions: bindActionCreators(GridActions, dispatch)
  };
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App);

我已经验证正确修改的日期对象正在到达减速器 - 但是 gridAppState 似乎停留在我加载的初始日期。

在依赖附加事件处理程序和当前应用程序状态的 redux 中处理异步逻辑的正确方法是什么?有没有正确的方法来做这三个?

【问题讨论】:

    标签: asynchronous reactjs q redux redux-thunk


    【解决方案1】:

    您应该处理组件中的事件并根据按下的键调用正确的操作。

    因此,当您调度异步操作时,您可以执行类似的操作

    export default function getNextPhoto(currentDate) {
      return (dispatch) => {
        const newDate = calculateNewDate(currentDate);
    
        dispatch(requestNewPhoto(newDate));
    
        return photosService.getPhotoOfDate(newDate)
        .then((response) => {
          dispatch(newPhotoReceived(response.photoURL);
        });
      };
    }
    

    您应该处理组件上的 keypress 事件,并在您知道需要获取新照片时发送您的操作。

    你的应用看起来像

    class App extends React.Component {
      componentDidMount() {
        const { gridAppState, actions } = this.props;
        document.addEventListener("keydown", function() {
          if (event.which == 37) {
            actions.getNextPhoto(gridAppState.date);
          } else if (...) {
            actions.getPrevPhoto(gridAppState.date);
          }
    
          // etc
        });
      }
    }
    

    顺便说一句,您仍然缺少在 Redux Store 中更新您的状态的 reducer。

    【讨论】:

    • 我实际上认为在哪里处理哪个键绑定并不重要,但我想我可以通过将逻辑转移到事件处理函数中来避免向商店发出“NOACTION”动作。我省略了减速器,因为我很确定它们可以工作——在没有异步逻辑的情况下对它们进行了测试,并且一切似乎都运行良好。您是否建议我将两个状态更改拆分为一个立即发生并更新应用程序状态的日期概念的调度,以及一个仅在我执行异步工作后才解决的调度?我认为动作创作者必须返回 POJO..
    • 他们确实做到了。例如,requesetNewPhoto 动作创建者可以返回{ type: 'REQUEST_NEW_PHOTO', photoDate: newDate },然后在商店中您会获得该信息并更新商店。存储当前状态:{ isLoading: false, currentDate: object, photoURL: 'http..' } 我们调用 requestNewPhoto 动作,新状态是 { isLoading: true, currentDate: newDate, photoURL: null } 我们调用 newPhotoReceived 并再次更新存储。当然,每次更新商店时,都会在您的组件中进行新的渲染,以反映新的状态。
    • 是的,异步操作是在同步操作发生时调度同步操作的操作。所以getNextPhoto() 是一个触发两个同步操作的异步操作。 More info.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-28
    • 2021-09-14
    相关资源
    最近更新 更多