获取失败导致无限组件 life-cycle 循环
Failed fetch causes infinite component life-cycle loop
有了一个连接的容器,我有一个由高阶减速器(如下所示)包装的减速器来捕获和处理错误。在 componentDidMount
期间调用提取请求失败时,连接的容器将自行卸载 componentWillUnmount
。这会导致容器中出现无限循环,因为它将再次挂载,获取失败,并且容器将自行卸载。
知道为什么在连接组件中使用高阶减速器会导致这种情况吗?
处理高阶减速器时出错:
export const errorHandler = (reducer: (state: any, action: { type: string }, initialState: any) => {}) => {
const errorState = fromJS({
error: {
hasError: false,
message: "",
},
});
const initialState = errorState.merge(reducer(undefined, { type: undefined }, undefined));
return (state = initialState, action) => {
switch (action.type) {
case ACTIONS.SET_ERROR:
return state.setIn(["error", "hasError"], true)
.setIn(["error", "message"], action.message);
case ACTIONS.CLEAR_ERROR:
return state.set("error", errorState.get("error"));
default:
return reducer(state, action, initialState);
}
};
};
示例容器:
class Page extends Component {
componentDidMount() {
this.props.fetch(....);
}
componentWillUnmount() {
this.props.clearData();
this.props.cancelRequests();
}
}
export default connect(
(state) => ({
error: state.data.get("error", ""),
}),
{
clearError,
clearData,
cancelRequests,
},
)(Page);
减速机示例:
export fetch = () => ({
type: ACTIONS.FETCH
});
export default errorHandler((state, action) => {
switch(action.type) {
default:
return state;
}
}));
史诗级:
export const fetch = (action$: any, store: any, api: API) => {
return action$.ofType(ACTIONS.FETCH)
.mergeMap((action: any) =>
fromPromise(api.fetch(action.data))
.pluck("Data")
.map(data) =>
fetchFulfilled(data),
)
.catch((response) => {
const toPromise = typeof response.json === "function" ? response.json() : new Promise((resolve) => resolve(response));
return fromPromise(toPromise)
.pluck("Message")
.map((Message: string) =>
setError(Message));
})
.takeUntil(action$.ofType(ACTIONS.CANCEL_REQUESTS)));
};
我认为你只需要捕获错误而不是让异常被 React 挂载代码捕获。
try {
this.props.fetch(....);
}
catch (e) {
//Do whatever is appropriate to handle the fetch failure. Maybe you want...
this.setState({ error: {hasError: true, message: '' + e});
}
我认为上面的 setState() 调用不适合您预期的 reducer 实现,但这是一个您可以解决的单独问题(或提出更多相关问题)。您的问题的主要部分似乎是停止 unmount/remount 行为。
根据我们在评论中的对话:
通常组件会卸载,因为它们的 parent 不再呈现它们。 parent 是什么样子的?您可能会在此处查找组件卸载的原因。
我不知道在任何情况下组件可以自行卸载(无需破解)
有了一个连接的容器,我有一个由高阶减速器(如下所示)包装的减速器来捕获和处理错误。在 componentDidMount
期间调用提取请求失败时,连接的容器将自行卸载 componentWillUnmount
。这会导致容器中出现无限循环,因为它将再次挂载,获取失败,并且容器将自行卸载。
知道为什么在连接组件中使用高阶减速器会导致这种情况吗?
处理高阶减速器时出错:
export const errorHandler = (reducer: (state: any, action: { type: string }, initialState: any) => {}) => {
const errorState = fromJS({
error: {
hasError: false,
message: "",
},
});
const initialState = errorState.merge(reducer(undefined, { type: undefined }, undefined));
return (state = initialState, action) => {
switch (action.type) {
case ACTIONS.SET_ERROR:
return state.setIn(["error", "hasError"], true)
.setIn(["error", "message"], action.message);
case ACTIONS.CLEAR_ERROR:
return state.set("error", errorState.get("error"));
default:
return reducer(state, action, initialState);
}
};
};
示例容器:
class Page extends Component {
componentDidMount() {
this.props.fetch(....);
}
componentWillUnmount() {
this.props.clearData();
this.props.cancelRequests();
}
}
export default connect(
(state) => ({
error: state.data.get("error", ""),
}),
{
clearError,
clearData,
cancelRequests,
},
)(Page);
减速机示例:
export fetch = () => ({
type: ACTIONS.FETCH
});
export default errorHandler((state, action) => {
switch(action.type) {
default:
return state;
}
}));
史诗级:
export const fetch = (action$: any, store: any, api: API) => {
return action$.ofType(ACTIONS.FETCH)
.mergeMap((action: any) =>
fromPromise(api.fetch(action.data))
.pluck("Data")
.map(data) =>
fetchFulfilled(data),
)
.catch((response) => {
const toPromise = typeof response.json === "function" ? response.json() : new Promise((resolve) => resolve(response));
return fromPromise(toPromise)
.pluck("Message")
.map((Message: string) =>
setError(Message));
})
.takeUntil(action$.ofType(ACTIONS.CANCEL_REQUESTS)));
};
我认为你只需要捕获错误而不是让异常被 React 挂载代码捕获。
try {
this.props.fetch(....);
}
catch (e) {
//Do whatever is appropriate to handle the fetch failure. Maybe you want...
this.setState({ error: {hasError: true, message: '' + e});
}
我认为上面的 setState() 调用不适合您预期的 reducer 实现,但这是一个您可以解决的单独问题(或提出更多相关问题)。您的问题的主要部分似乎是停止 unmount/remount 行为。
根据我们在评论中的对话:
通常组件会卸载,因为它们的 parent 不再呈现它们。 parent 是什么样子的?您可能会在此处查找组件卸载的原因。
我不知道在任何情况下组件可以自行卸载(无需破解)