YAOTU INSIGHTS

ng-redux异步数据加载完全教程:redux-thunk与AngularJS $http实战指南

ng-redux异步数据加载完全教程:redux-thunk与AngularJS $http实战指南
【免费下载链接】ng-reduxAngular bindings for Redux项目地址https://gitcode.com/gh_mirrors/ng/ng-redux点击查看免费下载在 AngularJS 项目里做 Redux 异步数据加载ng-redux是官方推荐的绑定方案。本教程基于仓库内置的 Reddit 新闻加载示例examples/async/带你从零看懂ng-redux如何配合redux-thunk中间件和 AngularJS 的$http完成「点击选择 → 发起请求 → 更新 loading 状态 → 渲染列表」这一完整异步链路并学会防止重复请求的实战技巧。一、项目结构异步示例长什么样ng-redux 仓库提供了一个专门的异步示例所有代码集中在examples/async/目录下职责划分非常清晰文件职责index.js应用入口注册$ngReduxProvider与 thunk 中间件actions/asyncService.js同步/异步 action creator核心逻辑constants/ActionTypes.jsaction type 常量定义reducers/index.js管理 loading / 数据 / 失效标记的 reducercontainers/app.js用connect()连接 Redux 的容器组件components/posts.html纯展示的列表组件理解这套分层constants → actions → reducers → containers → components你就掌握了 Redux 异步编程的通用范式。 核心思想组件不直接调接口而是dispatch 一个异步 action接口请求由 thunk 中间件执行结果再以同步 action 的形式写回 storeUI 自动跟随刷新。二、接入 redux-thunk一行代码打通异步能力ng-redux 提供了三种初始化 store 的方式异步示例采用的是最便捷的createStoreWith见 index.jsangular.module(async, [ngRedux]) .config(($ngReduxProvider) { $ngReduxProvider.createStoreWith(rootReducer, [thunk, createLogger()]); })这里的关键是第二个参数[thunk, createLogger()]thunk让 action creator 可以返回函数而不是普通 action 对象。这是异步请求的基础源码实现见 ngRedux.js 中的createStoreWith。createLogger()redux-logger把每个 action 打印到控制台方便排查。在 ng-redux 内部这些中间件最终会被applyMiddleware包裹并且框架会自动把digestMiddleware追加到末尾见 ngRedux.js——它负责在每次 dispatch 后触发$rootScope.$digest()保证 store 更新能同步到视图。你不需要手动写$digest这是 ng-redux 相对原生 Redux 最省心的一点。三、action creator 的三种形态从同步到异步打开 asyncService.js你会看到从简单到复杂的三类写法。1. 同步 action creator普通状态变更比如选择板块时发出的selectRedditasyncService.jsfunction selectReddit(reddit) { return { type: types.SELECT_REDDIT, reddit }; }返回的就是一个带type的对象reducer 直接消费。2. 异步 thunkdispatch $http 组合拳真正发起网络请求的是fetchPostsasyncService.jsfunction fetchPosts(reddit) { return dispatch { dispatch(requestPosts(reddit)); // ① 先标记 loading return $http.get(http://www.reddit.com/r/${reddit}.json) .then(response response.data) .then(json dispatch(receivePosts(reddit, json))); // ② 请求回来再写回数据 }; }这里有三点值得注意函数返回的是dispatch {...}这就是 thunk 中间件识别并执行的函数形态。请求发出前先dispatch(requestPosts(...))置isFetching trueUI 立刻显示 Loading...。请求用 AngularJS 的$http通过构造函数注入返回的 Promise 在.then中再dispatch(receivePosts(...))完成收尾。receivePosts会把接口返回的列表规整成posts数组并记录receivedAt时间戳asyncService.js。3. 智能 thunk带 getState 判断避免重复请求这是整个示例的精髓fetchPostsIfNeededasyncService.jsfunction fetchPostsIfNeeded(reddit) { return (dispatch, getState) { if (shouldFetchPosts(getState(), reddit)) { return dispatch(fetchPosts(reddit)); } }; }注意 thunk 函数接收了两个参数dispatch和getState——getState允许你在发起请求前先看一眼当前 store判断值不值得请求。判断逻辑shouldFetchPosts如下asyncService.jsfunction shouldFetchPosts(state, reddit) { const posts state.postsByReddit[reddit]; if (!posts) return true; // 从没加载过 → 必须请求 if (posts.isFetching) return false; // 正在请求中 → 别重复发 return posts.didInvalidate; // 已失效才重新请求 }这就解决了异步场景里最常见的两个坑重复请求和竞态。四、reducer 如何管理异步状态异步加载天然需要三个状态位isFetching是否正在请求、didInvalidate数据是否已失效、items数据本体。示例的 reducer 用它们刻画了一个清晰的状态机见 reducers/index.jscase REQUEST_POSTS: // 请求发出 return Object.assign({}, state, { isFetching: true, didInvalidate: false }); case RECEIVE_POSTS: // 数据到达 return Object.assign({}, state, { isFetching: false, items: action.posts, lastUpdated: action.receivedAt });同时通过postsByReddit这个按板块分组的字典结构reducers/index.js把每个板块的加载状态彼此隔离最后用combineReducers汇总成根 reducer。 这套isFetching / didInvalidate / items三件套是 Redux 异步数据的经典模式几乎可以套用到任何列表 刷新场景。五、connect 连接组件让 UI 自动跟随 store一切异步数据最终要落到视图。ng-redux 的核心 API 是$ngRedux.connect(mapStateToTarget, mapDispatchToTarget)(target)容器组件 app.js 的写法constructor($ngRedux, AsyncActions) { const unsubscribe $ngRedux.connect(this.mapStateToThis, AsyncActions)( (selectedState, actions) { Object.assign(this, selectedState, actions); } ); this.fetchPostsIfNeeded(this.selectedReddit); // 初始化先拉一次 }mapStateToThis声明组件需要 store 里的哪些字段app.js只挑选selectedReddit、posts、isFetching、lastUpdated避免把整个 store 灌进视图。AsyncActions把 action creator 对象传进去connect 会自动把它们绑定好 dispatch组件里可以直接this.fetchPostsIfNeeded(...)调用。connect的订阅、浅比较shallowEqual、以及按需更新逻辑实现在 connector.js——只有mapStateToThis的返回值真正发生变化时才会触发一次更新。视图如何根据状态切换模板 app.html 完全靠状态位驱动非常干净h2 ng-showapp.isFetching app.posts.length 0Loading.../h2 h2 ng-show!app.isFetching app.posts.length 0Empty./h2 div ng-showapp.posts.length 0 ng-style{ opacity: app.isFetching ? 0.5 : 1 } ngr-posts postsapp.posts/ngr-posts /div刷新按钮的逻辑也很典型——先invalidateReddit标记数据失效再立即fetchPostsIfNeededapp.jshandleRefreshClick() { this.invalidateReddit(this.selectedReddit); this.fetchPostsIfNeeded(this.selectedReddit); }切换板块时componentWillReceiveStateAndActions监听到selectedReddit变化也会自动触发一次按需加载app.js。六、最佳实践清单 ⭐结合以上源码异步数据加载可以沉淀为几条可复用经验请求前必置 loading先dispatch(requestXxx)再发请求UI 才有即时反馈。用 getState 做按需加载fetchPostsIfNeeded模式能天然规避重复请求与竞态。失效标记要显式刷新不是重新请求而是标记失效 按需重取语义更清晰。组件只订阅需要的切片mapStateToThis返回最小字段集配合浅比较降低无谓更新。别忘记取消订阅组件销毁时调用connect返回的unsubscribeREADME 中推荐$scope.$on($destroy, unsubscribe)避免内存泄漏。 调试建议示例已通过createLogger()打印所有 action。如需图形化时间旅行调试counter 示例展示了接入 Redux DevTools 的方式见 devTools.js 与 index.js异步示例可照搬。七、快速跑起来异步示例依赖redux-thunk、redux-logger、ng-redux、angular见 package.json。启动本地开发服务器cd examples/async npm install npm startnpm start会执行webpack-dev-server配置见 webpack.config.js浏览器打开后就能体验切换板块 → 加载动画 → 列表渲染的完整异步流程。小结ng-redux 让 AngularJS 与 Redux 的异步协作变得异常直接thunk 承载异步逻辑、$http负责网络、reducer 管理状态、connect驱动视图。把examples/async/这一套REQUEST → RECEIVE → NEEDS_REFRESH的范式吃透你就能在绝大多数 AngularJS Redux 项目里优雅地处理异步数据加载。赞分享【免费下载链接】ng-reduxAngular bindings for Redux项目地址https://gitcode.com/gh_mirrors/ng/ng-redux点击查看免费下载相关推荐Redux-Thunk实战教程构建完整的异步数据请求流程Redux Thunk实战教程构建完整的异步数据请求流程 你是否还在为Redux中异步操作的复杂性而困扰当需要处理AJAX请求、定时器或其他异步任务时是否前端Redux-Thunk与React Native地图异步加载地理位置数据Redux Thunk与React Native地图异步加载地理位置数据 你是否在React Native地图应用中遇到过地理位置数据加载缓慢、界面卡顿的问题前端如何使用Redux-Thunk实现高效的国际化语言包异步加载如何使用Redux Thunk实现高效的国际化语言包异步加载 Redux Thunk是Redux生态中最流行的中间件之一它允许你编写返回函数而非action对前端创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考