如何使用 redux 在首次渲染期间指示异步操作的 "loading" 状态
How to indicate "loading" state for an async action during first render using redux
假设我有一个如下所示的 redux 模块:
import fetch from 'isomorphic-fetch';
// CONSTANTS
const LOAD = 'LOAD';
const LOAD_SUCCESS = 'LOAD_SUCCESS';
// REDUCER
const initialState = { loading: false, data: [] };
export default function reducer(state = initialState, action) {
switch (action.type) {
case LOAD: return { ...state, loading: true };
case LOAD_SUCCESS: return { ...state, loading: false, data: action.data };
default: return state;
}
}
// ACTION CREATORS
function requestLocations() {
return { type: LOAD };
}
function receiveLocations(json) {
return { type: LOAD_SUCCESS, data: json };
}
export function fetchLocations() {
return function (dispatch) {
dispatch(requestLocations());
return fetch('http://myurl')
.then(response => response.json())
.then(json => dispatch(receiveLocations(json)));
};
}
如果我在 componentWillMount 中进行异步调用,我会在第一次渲染时遇到 loading
状态。想象一下我的组件看起来像这样(为简洁起见进行了简化):
export default class LocationContainer extends React.Component {
componentWillMount() {
fetchLocations(); // already bound and injected via connect.
}
render() {
const { loading, data } = this.props; // injected via connect from reducer above.
if (loading) {
return <Spinner />;
} else {
return <LocationExplorer locations={ data } />;
}
}
}
我 运行 遇到的问题是,在 LocationContainer
的第一次渲染中,loading
是假的,并且 data
还没有被提取。在 componentWillMount
中,LOAD
动作被触发,loading
的道具更改被设置为 true 排队等待在后续渲染中发生。与此同时,在我的第一次渲染中,当我真正想要 Spinner
而不是 LocationExplorer
时渲染了 LocationExplorer
,因为 loading
仍然是错误的。我想知道你如何在不设置 firstRender = true
状态变量 hack 的情况下处理这个问题。
不要在 componentWillMount
中提出请求。相反,请在安装组件之前执行此操作。例如
store.dispatch(fetchLocations());
ReactDOM.render(<App store={store} />, mountpoint);
一个选项可以使用 data
初始状态扩展 loading
条件:
const initialState = { loading: false, data: [] };
当您 loading
而您的 data
为空时,这意味着您正处于等待新数据到来的确切状态:
if (loading && data.length === 0) {
return <Spinner />;
} else {
此外,我通常将异步调用放在 componentDidMount
而不是 componentWillMount
。
除了公认的答案之外,我们一直在使用并取得巨大成功的另一种解决方案是向 reducer 添加一个 complete
布尔标志,如果响应在某个时候返回,我们将其标记为真。如果响应实际返回一个空数组,这会使事情变得更加明确。 complete
标志让我知道响应来自服务器,而不仅仅是我的初始状态。
if(loading && !complete) {
return <Spinner />;
} else {
return <Component data={data} />;
}
我想我会添加这个以防它对其他人有帮助。
假设我有一个如下所示的 redux 模块:
import fetch from 'isomorphic-fetch';
// CONSTANTS
const LOAD = 'LOAD';
const LOAD_SUCCESS = 'LOAD_SUCCESS';
// REDUCER
const initialState = { loading: false, data: [] };
export default function reducer(state = initialState, action) {
switch (action.type) {
case LOAD: return { ...state, loading: true };
case LOAD_SUCCESS: return { ...state, loading: false, data: action.data };
default: return state;
}
}
// ACTION CREATORS
function requestLocations() {
return { type: LOAD };
}
function receiveLocations(json) {
return { type: LOAD_SUCCESS, data: json };
}
export function fetchLocations() {
return function (dispatch) {
dispatch(requestLocations());
return fetch('http://myurl')
.then(response => response.json())
.then(json => dispatch(receiveLocations(json)));
};
}
如果我在 componentWillMount 中进行异步调用,我会在第一次渲染时遇到 loading
状态。想象一下我的组件看起来像这样(为简洁起见进行了简化):
export default class LocationContainer extends React.Component {
componentWillMount() {
fetchLocations(); // already bound and injected via connect.
}
render() {
const { loading, data } = this.props; // injected via connect from reducer above.
if (loading) {
return <Spinner />;
} else {
return <LocationExplorer locations={ data } />;
}
}
}
我 运行 遇到的问题是,在 LocationContainer
的第一次渲染中,loading
是假的,并且 data
还没有被提取。在 componentWillMount
中,LOAD
动作被触发,loading
的道具更改被设置为 true 排队等待在后续渲染中发生。与此同时,在我的第一次渲染中,当我真正想要 Spinner
而不是 LocationExplorer
时渲染了 LocationExplorer
,因为 loading
仍然是错误的。我想知道你如何在不设置 firstRender = true
状态变量 hack 的情况下处理这个问题。
不要在 componentWillMount
中提出请求。相反,请在安装组件之前执行此操作。例如
store.dispatch(fetchLocations());
ReactDOM.render(<App store={store} />, mountpoint);
一个选项可以使用 data
初始状态扩展 loading
条件:
const initialState = { loading: false, data: [] };
当您 loading
而您的 data
为空时,这意味着您正处于等待新数据到来的确切状态:
if (loading && data.length === 0) {
return <Spinner />;
} else {
此外,我通常将异步调用放在 componentDidMount
而不是 componentWillMount
。
除了公认的答案之外,我们一直在使用并取得巨大成功的另一种解决方案是向 reducer 添加一个 complete
布尔标志,如果响应在某个时候返回,我们将其标记为真。如果响应实际返回一个空数组,这会使事情变得更加明确。 complete
标志让我知道响应来自服务器,而不仅仅是我的初始状态。
if(loading && !complete) {
return <Spinner />;
} else {
return <Component data={data} />;
}
我想我会添加这个以防它对其他人有帮助。