根据文档,"没有中间件,Redux商店只支持同步数据流".我不明白为什么会这样.为什么容器组件不能调用异步API,然后调用dispatch操作?
例如,想象一个简单的UI:字段和按钮.当用户按下按钮时,该字段将填充来自远程服务器的数据.
import * as React from 'react';
import * as Redux from 'redux';
import { Provider, connect } from 'react-redux';
const ActionTypes = {
STARTED_UPDATING: 'STARTED_UPDATING',
UPDATED: 'UPDATED'
};
class AsyncApi {
static getFieldValue() {
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve(Math.floor(Math.random() * 100));
}, 1000);
});
return promise;
}
}
class App extends React.Component {
render() {
return (
<div>
<input value={this.props.field}/>
<button disabled={this.props.isWaiting} onClick={this.props.update}>Fetch</button>
{this.props.isWaiting && <div>Waiting...</div>}
</div>
); …Run Code Online (Sandbox Code Playgroud) 我一直在努力寻找解决这个问题的方法......
我正在开发一个带有在线记分牌的游戏.玩家可以随时登录和注销.完成游戏后,玩家将看到记分牌,并查看自己的排名,并自动提交分数.
记分牌显示了玩家的排名和排行榜.
当用户完成播放(提交分数)以及用户只想查看他们的排名时,使用记分板.
这是逻辑变得非常复杂的地方:
如果用户已登录,则将首先提交分数.保存新记录后,将加载记分板.
否则,将立即加载记分板.玩家将获得登录或注册的选项.之后,将提交分数,然后记分板将再次刷新.
但是,如果没有要提交的分数(只需查看高分表).在这种情况下,只需下载播放器的现有记录.但由于此操作不会影响记分牌,因此记分牌和玩家记录应同时下载.
有无限数量的级别.每个级别都有不同的记分牌.当用户查看记分板时,用户正在"观察"该记分板.当它关闭时,用户停止观察它.
用户可以随时登录和注销.如果用户注销,则用户的排名应该消失,如果用户以另一个帐户登录,则应该获取并显示该帐户的排名信息.
...但是,此信息只应针对用户当前正在观察的记分板进行.
对于查看操作,结果应缓存在内存中,以便如果用户重新订阅同一记分板,则不会提取.但是,如果提交了分数,则不应使用缓存.
任何这些网络操作都可能失败,并且播放器必须能够重试它们.
这些操作应该是原子的.所有状态都应该一次更新(没有中间状态).
目前,我能够使用Bacon.js(功能性反应式编程库)来解决这个问题,因为它提供了原子更新支持.代码非常简洁,但现在它是一个混乱的不可预测的意大利面条代码.
我开始看Redux.所以我尝试构建商店,并想出了类似的东西(用YAMLish语法):
user: (user information)
record:
level1:
status: (loading / completed / error)
data: (record data)
error: (error / null)
scoreboard:
level1:
status: (loading / completed / error)
data:
- (record data)
- (record data)
- (record data)
error: (error / null)
Run Code Online (Sandbox Code Playgroud)
问题变成:我在哪里放置副作用.
对于无副作用的动作,这变得非常容易.例如,在LOGOUT行动时,record减速器可以简单地将所有记录都抛出.
但是,某些行为确实有副作用.例如,如果我在提交分数之前没有登录,那么我成功登录,该SET_USER操作将用户保存到商店中.
但是因为我有一个要提交的分数,这个SET_USER动作也必须引发一个AJAX请求,同时设置record.levelN.status为loading.
问题是:当我以原子方式登录时,我如何表示应该发生副作用(得分提交)?
在Elm架构中,更新程序在使用形式时也会发出副作用 …
Redux Thunk和Redux Saga都是Redux的中间件.两者之间有什么区别以及如何确定何时使用Redux Thunk或Redux Saga?
在编写redux-thunk函数时,称为thunks,有很多样板可以很容易地被抽象掉.例如,在我们的大多数异步API调用中,我们正在执行以下操作,没有任何副作用:
export const LOGIN_REQUEST = 'my-app/auth/LOGIN_REQUEST';
export const LOGIN_RECIEVE = 'my-app/auth/LOGIN_RECIEVE';
export const LOGIN_FAILURE = 'my-app/auth/LOGIN_FAILURE';
// ... reducer code here
export function login(loginHandle, password) {
return (dispatch, getState, api) => {
dispatch({ type: LOGIN_REQUEST });
api.post('/auth/login', { loginHandle, password }).then(
response => dispatch({ type: LOGIN_RECIEVE, response }),
error => dispatch({ type: LOGIN_FAILURE, error })
);
};
}
Run Code Online (Sandbox Code Playgroud)
简单!虽然因为这涵盖了我们至少70%的请求,但我确信有一种优雅的方法可以将上述代码抽象为类似的东西(伪代码):
export function login(loginHandle, password) {
return (dispatch, getState, api) => api('POST', LOGIN_REQUEST, '/auth/login', { loginHandle, password }); …Run Code Online (Sandbox Code Playgroud) 我开始学习钩子。但我不明白如何正确使用异步调用。早些时候我用过
import * as actionQR from "../actions/qr";
...
function mapDispatchToProps(dispatch) {
return {
actionQR: bindActionCreators(actionQR, dispatch),
}
}
Run Code Online (Sandbox Code Playgroud)
在调用 my 之后this.props.actionQR.myFunc(),我应该用 useDispatch() 做什么?如果我只是打电话
import {foo} from "../actions/qr";
...
useDispatch(foo());
Run Code Online (Sandbox Code Playgroud)
那么我foo()不console.log(2)
export const foo = () => {
console.log(1);
return (dispatch) => {
console.log(2);
}
}
Run Code Online (Sandbox Code Playgroud)
我使用 thunk
import createRootReducer from './reducers/index';
...
const store = createStore(createRootReducer, applyMiddleware(thunk));
Run Code Online (Sandbox Code Playgroud) redux ×5
reactjs ×4
javascript ×3
redux-thunk ×3
react-redux ×2
asynchronous ×1
flux ×1
react-hooks ×1
redux-saga ×1