处理不将结果存储在状态中的异步操作
Handle async actions that do not store result in state
我偶然发现了一个 vanilla JS webapp 部分的需求,它需要一个 JSON "definitions" 对象来呈现。定义在最开始通过HTTP
请求加载、读取、解析并传递给另一层应用。对象本身在其整个生命周期中永远不会改变。
我现在正尝试在 ReactJS, using Redux + redux-thunk 中模拟此场景。我创建了一个 thunk/async 操作来获取 JSON 对象,提取它需要的东西并最终更新状态 -
但它确实不在状态中存储对象本身。这似乎是正确的、合乎逻辑的方法,因为如前所述,定义永远不会以任何方式修改。我认为它只是不是严格意义上的状态。
然而,通过做出那个决定,我最终在实施实际 React.Component
时遇到了困难。几乎每一个 example 我在野外都见过这样的异步情况:
- 定义一个触发某些 API 调用的 thunk 动作。
- 以 属性.
状态存储他们取回(或经过一些更改后)的任何内容
- 在具有
mapStateToProps
和 connect
的组件中将 属性 映射到 this.props
。
在我的例子中,我真的没有状态 属性 可以绑定到 。所以我最终在我的异步操作中返回了定义对象,并使用组件的本地状态来获得我需要的东西。
class ContainerComponent extends React.Component {
state = { definitions: {} };
componentDidMount() {
const { dispatch } = this.props;
dispatch(fetchDefinitions())
.then((definitions) => this.setState({ definitions }));
}
render() {
return (<PresentationalComponent definitions={this.state.definitions} />);
}
}
export default connect()(ContainerComponent);
并不是说 this.setState
应该 be avoided,但这看起来非常像 我在引入 Redux 之前所拥有的:一个 API 调用返回一个承诺 - 只有更多的间接干预。
componentDidMount() {
const { dispatch } = this.props;
fetch(`${API_URL}/definitions`)
.then((res) => res.json())
.then((definitions) => this.setState({ definitions }));
}
那么,我应该怎么做呢?我在这里缺少什么特别的东西吗?我应该遵循什么模式?也许,为了这件事完全避免使用 Redux?
您说得对,拥有组件状态不一定是坏事,但我相信您对 API 调用后将数据存储在哪里感到困惑。
你提到它不一定是状态,但我不这么认为。在进行 API 调用之前,您的应用程序没有该数据。您可能在应用程序启动时有某些 UX/UI 指示,例如可以指示是否正在获取数据:definitions.all.isFetching
.
在您的 componentDidMount
中,调度获取数据的操作是正确的。触发操作并收到成功响应后,您的 reducer 应该将定义保存到您的 redux 存储中,如
import { assign, get } from 'lodash';
const all = (
state = { isFetching: false, data: [] },
action,
) => {
switch (action.type) {
case types.LIST_DEFINITIONS:
return assign({}, state, { isFetching: true });
case types.LIST_DEFINITIONS_SUCCESS:
return assign({}, state, get(action, 'result.data'), { isFetching: false });
default: return state;
}
};
然后在你的组件中,你会 connect
你的 redux store
function mapStateToProps(state){
return {
definitions: state.definitions.all.data
};
}
export default connect(mapStateToProps, { listDefinitions })(ContainerComponent);
另请注意,我将示例中的操作移出,并将其放入与 mapDispatchToProps
shorthand 的连接中。
我偶然发现了一个 vanilla JS webapp 部分的需求,它需要一个 JSON "definitions" 对象来呈现。定义在最开始通过HTTP
请求加载、读取、解析并传递给另一层应用。对象本身在其整个生命周期中永远不会改变。
我现在正尝试在 ReactJS, using Redux + redux-thunk 中模拟此场景。我创建了一个 thunk/async 操作来获取 JSON 对象,提取它需要的东西并最终更新状态 - 但它确实不在状态中存储对象本身。这似乎是正确的、合乎逻辑的方法,因为如前所述,定义永远不会以任何方式修改。我认为它只是不是严格意义上的状态。
然而,通过做出那个决定,我最终在实施实际 React.Component
时遇到了困难。几乎每一个 example 我在野外都见过这样的异步情况:
- 定义一个触发某些 API 调用的 thunk 动作。
- 以 属性. 状态存储他们取回(或经过一些更改后)的任何内容
- 在具有
mapStateToProps
和connect
的组件中将 属性 映射到this.props
。
在我的例子中,我真的没有状态 属性 可以绑定到 。所以我最终在我的异步操作中返回了定义对象,并使用组件的本地状态来获得我需要的东西。
class ContainerComponent extends React.Component {
state = { definitions: {} };
componentDidMount() {
const { dispatch } = this.props;
dispatch(fetchDefinitions())
.then((definitions) => this.setState({ definitions }));
}
render() {
return (<PresentationalComponent definitions={this.state.definitions} />);
}
}
export default connect()(ContainerComponent);
并不是说 this.setState
应该 be avoided,但这看起来非常像 我在引入 Redux 之前所拥有的:一个 API 调用返回一个承诺 - 只有更多的间接干预。
componentDidMount() {
const { dispatch } = this.props;
fetch(`${API_URL}/definitions`)
.then((res) => res.json())
.then((definitions) => this.setState({ definitions }));
}
那么,我应该怎么做呢?我在这里缺少什么特别的东西吗?我应该遵循什么模式?也许,为了这件事完全避免使用 Redux?
您说得对,拥有组件状态不一定是坏事,但我相信您对 API 调用后将数据存储在哪里感到困惑。
你提到它不一定是状态,但我不这么认为。在进行 API 调用之前,您的应用程序没有该数据。您可能在应用程序启动时有某些 UX/UI 指示,例如可以指示是否正在获取数据:definitions.all.isFetching
.
在您的 componentDidMount
中,调度获取数据的操作是正确的。触发操作并收到成功响应后,您的 reducer 应该将定义保存到您的 redux 存储中,如
import { assign, get } from 'lodash';
const all = (
state = { isFetching: false, data: [] },
action,
) => {
switch (action.type) {
case types.LIST_DEFINITIONS:
return assign({}, state, { isFetching: true });
case types.LIST_DEFINITIONS_SUCCESS:
return assign({}, state, get(action, 'result.data'), { isFetching: false });
default: return state;
}
};
然后在你的组件中,你会 connect
你的 redux store
function mapStateToProps(state){
return {
definitions: state.definitions.all.data
};
}
export default connect(mapStateToProps, { listDefinitions })(ContainerComponent);
另请注意,我将示例中的操作移出,并将其放入与 mapDispatchToProps
shorthand 的连接中。