无法在 React-Redux 应用程序中调用另一个操作
Cannot call one action from another in a React-Redux app
我有一个登录模式。我使用 action creator 在 reducers 中将 isLoginModalVisible: true 变为 true。在容器内调用动作创建器,在组件的 onClick 内,像这样:
<TextButtonRight onClick={()=> this.props.showLoginModal(true)}>
在登录模式中,我有一个提交表单的登录按钮。我希望模式在 200OK 时消失,否则,我会在模式中显示一条错误消息。在登录按钮上调用此动作创建器单击:
export function logInUser(){
console.log("Actions--> logInUser");
//Imagine I got a 200OK
dispatch(showLoginModal(false));
return({
type: UPDATE_USER_LOGGED_IN,
payload: true
});
}
我正在调用操作创建器以隐藏 logInUser 操作创建器的模态,但它不起作用。 showLoginModal 动作创建者确实被击中,但它没有分派给 reducer。
这是 showLoginModal 操作创建者:
export function showLoginModal(bool){
console.log("Actions--> showLoginModal:"+bool);
return({
type: UPDATE_LOGIN_MODAL_VISIBLE,
payload: bool
});
}
(如果我犯了菜鸟错误,我很抱歉)
编辑:
我的 reducer.It 的一部分确实有效,因为这就是我显示登录模式的方式。当我想隐藏它时,我传递 false。有效载荷也没有问题。当我通过另一个动作创建者调用它时,console.log 没有得到。当我以这种方式将它传递给提交按钮上的 onClick 时工作正常:
onClick={()=> this.props.showLoginModal(false)}
case UPDATE_LOGIN_MODAL_VISIBLE:
console.log("REDUCER-->"+UPDATE_LOGIN_MODAL_VISIBLE);
return {...state, loginModalVisible: action.payload};
break;
组合减速器:
const rootReducer = combineReducers({
posts: postsReducer,
displayComps: displayComponentsReducer,
form: formReducer,
searchForm: searchFormReducer
});
编辑 2:
抱歉,我应该提到我正在使用 thunk。我想知道是否有一种方法可以从这个调用一个动作,就像这样:
req.then((response)=>{
console.log("REQ_COMPLETE");
dispatch({type: UPDATE_USER_LOGGED_IN, payload: true});
//like so:
showLoginModal(false);
localStorage.setItem('userLoggedIn', true);
})
而不是添加这个:
dispatch({type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false});
从另一个动作创建者那里派发动作似乎有点老套。
你看过redux thunk了吗?它允许您将函数传递给 reducer,从而允许异步调用。
然后在你的动作创作者之一,你可以写这样的东西:
export const logUserIn () => {
return dispatch => {
fetch(/* hit login url*/)
.then(res => {/* switch on res here, if login worked
dispatch to hide modal, else show
error*/})
}
}
希望对您有所帮助。
我认为你的部分问题是你没有使用 Redux 中间件。
这是 redux 的创建者本人的一个很好的教程:Building React Applications with Idiomatic Redux
为了您的目的,如果您合并 Redux Thunk,您应该能够从一个动作创建者发送多个动作。
你可以这样做:
安装:
npm install --save redux-thunk
将其放入您的 store.js
文件
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
现在,您的动作创建器将有 dispatch
和 getState
可用。
export const showLoginModal = (bool) => {
console.log("Actions--> showLoginModal:"+bool);
return({
type: UPDATE_LOGIN_MODAL_VISIBLE,
payload: bool
});
}
export const loginUser = () => (dispatch, getState) => {
console.log("Actions--> logInUser");
// you have complete state available as getState(), but this is
// not a good design pattern, so use with caution
//Imagine I got a 200OK
dispatch(showLoginModal(false));
dispatch({
type: UPDATE_USER_LOGGED_IN,
payload: true
});
}
希望对您有所帮助。玩得开心。
澄清一些术语可能会有所帮助。如果这是您已经知道的内容,请提前致歉。
当你想用 redux-thunk 分派多个动作时,你分派一个 operation。这是一个常见的模式。看起来你的 logInUser()
函数是一个操作。有关规范示例,请参阅 fetchPostsIfNeeded()
in Dan Abramov's documentation here.
action creator 只是 return 一个对象,什么都不做。 operation 做一些事情(通常是异步的)然后分派动作,它通常通过调用动作创建者来构建。从操作中分派操作没有什么不好的。
但是,不建议从 action creator 调用任何函数。动作创建者应该 return 一个简单的对象并且没有副作用,就像您的 showLoginModal()
函数一样。请注意,调用动作创建器和手动创建对象之间没有行为差异。所以这样做:
var action = { type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false }
与
相同
var action = showLoginModal(false)
重要的是要注意:这两段代码都没有做任何事情!他们创建了一个对象,但不将其用于任何用途。在您 dispatch(action)
之前,您的应用程序不会发生任何事情。
动作创建者和操作都必须 dispatch()
ed。
- 操作必须被分派,因为它的内部函数就是这样传递给
dispatch
函数变量的,后者又用来分派操作。
- 必须调度操作,因为它们没有自己的功能;它们只是简单的对象。只有当它们被分派到 Redux store 时,它们才会影响 store 状态。
看起来你的这段代码正在调用一个动作创建者而不是调度它:
showLoginModal(false);
将其更改为
dispatch(showLoginModal(false));
可能会解决您的问题。
以一种有助于阅读代码的任何人(包括您)see/remember他们只是创建了一个动作的方式来命名动作创建者可能会有所帮助。例如,您可以将 showLoginModal
重命名为 showLoginModalAction
甚至 createShowLoginModalAction
.
logInUser()
函数是一个操作(因为它调度了一个动作),没有明确的原因,return 也是一个动作。 returns 的操作永远不会发送到商店,至少在发布的代码中是这样,所以它不会有任何效果。可能您的意图是将该操作发送到商店,那么为什么不直接发送它呢?
logInUser(){
dispatch( sendingLoginRequestAction() );
someAsyncLoginFuncThatReturnsAPromise(userName, password)
.then(result=>{
dispatch( loginSucceededAction(result) );
dispatch( hideLoginModalAction() );
});
}
那些动作创作者看起来像:
sendingLoginRequestAction() { return { type: UPDATE_SENDING_LOGIN_REQUEST }; } // You don't have anything like this, but it could be used to show a Waiting animation
loginSucceededAction() { return { type: UPDATE_USER_LOGGED_IN, payload: true }; }
hideDialogModalAction { return { type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false }; }
有帮助吗?
我有一个登录模式。我使用 action creator 在 reducers 中将 isLoginModalVisible: true 变为 true。在容器内调用动作创建器,在组件的 onClick 内,像这样:
<TextButtonRight onClick={()=> this.props.showLoginModal(true)}>
在登录模式中,我有一个提交表单的登录按钮。我希望模式在 200OK 时消失,否则,我会在模式中显示一条错误消息。在登录按钮上调用此动作创建器单击:
export function logInUser(){
console.log("Actions--> logInUser");
//Imagine I got a 200OK
dispatch(showLoginModal(false));
return({
type: UPDATE_USER_LOGGED_IN,
payload: true
});
}
我正在调用操作创建器以隐藏 logInUser 操作创建器的模态,但它不起作用。 showLoginModal 动作创建者确实被击中,但它没有分派给 reducer。
这是 showLoginModal 操作创建者:
export function showLoginModal(bool){
console.log("Actions--> showLoginModal:"+bool);
return({
type: UPDATE_LOGIN_MODAL_VISIBLE,
payload: bool
});
}
(如果我犯了菜鸟错误,我很抱歉)
编辑:
我的 reducer.It 的一部分确实有效,因为这就是我显示登录模式的方式。当我想隐藏它时,我传递 false。有效载荷也没有问题。当我通过另一个动作创建者调用它时,console.log 没有得到。当我以这种方式将它传递给提交按钮上的 onClick 时工作正常:
onClick={()=> this.props.showLoginModal(false)}
case UPDATE_LOGIN_MODAL_VISIBLE:
console.log("REDUCER-->"+UPDATE_LOGIN_MODAL_VISIBLE);
return {...state, loginModalVisible: action.payload};
break;
组合减速器:
const rootReducer = combineReducers({
posts: postsReducer,
displayComps: displayComponentsReducer,
form: formReducer,
searchForm: searchFormReducer
});
编辑 2:
抱歉,我应该提到我正在使用 thunk。我想知道是否有一种方法可以从这个调用一个动作,就像这样:
req.then((response)=>{
console.log("REQ_COMPLETE");
dispatch({type: UPDATE_USER_LOGGED_IN, payload: true});
//like so:
showLoginModal(false);
localStorage.setItem('userLoggedIn', true);
})
而不是添加这个:
dispatch({type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false});
从另一个动作创建者那里派发动作似乎有点老套。
你看过redux thunk了吗?它允许您将函数传递给 reducer,从而允许异步调用。
然后在你的动作创作者之一,你可以写这样的东西:
export const logUserIn () => {
return dispatch => {
fetch(/* hit login url*/)
.then(res => {/* switch on res here, if login worked
dispatch to hide modal, else show
error*/})
}
}
希望对您有所帮助。
我认为你的部分问题是你没有使用 Redux 中间件。 这是 redux 的创建者本人的一个很好的教程:Building React Applications with Idiomatic Redux
为了您的目的,如果您合并 Redux Thunk,您应该能够从一个动作创建者发送多个动作。
你可以这样做:
安装:
npm install --save redux-thunk
将其放入您的 store.js
文件
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
// Note: this API requires redux@>=3.1.0
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
现在,您的动作创建器将有 dispatch
和 getState
可用。
export const showLoginModal = (bool) => {
console.log("Actions--> showLoginModal:"+bool);
return({
type: UPDATE_LOGIN_MODAL_VISIBLE,
payload: bool
});
}
export const loginUser = () => (dispatch, getState) => {
console.log("Actions--> logInUser");
// you have complete state available as getState(), but this is
// not a good design pattern, so use with caution
//Imagine I got a 200OK
dispatch(showLoginModal(false));
dispatch({
type: UPDATE_USER_LOGGED_IN,
payload: true
});
}
希望对您有所帮助。玩得开心。
澄清一些术语可能会有所帮助。如果这是您已经知道的内容,请提前致歉。
当你想用 redux-thunk 分派多个动作时,你分派一个 operation。这是一个常见的模式。看起来你的 logInUser()
函数是一个操作。有关规范示例,请参阅 fetchPostsIfNeeded()
in Dan Abramov's documentation here.
action creator 只是 return 一个对象,什么都不做。 operation 做一些事情(通常是异步的)然后分派动作,它通常通过调用动作创建者来构建。从操作中分派操作没有什么不好的。
但是,不建议从 action creator 调用任何函数。动作创建者应该 return 一个简单的对象并且没有副作用,就像您的 showLoginModal()
函数一样。请注意,调用动作创建器和手动创建对象之间没有行为差异。所以这样做:
var action = { type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false }
与
相同var action = showLoginModal(false)
重要的是要注意:这两段代码都没有做任何事情!他们创建了一个对象,但不将其用于任何用途。在您 dispatch(action)
之前,您的应用程序不会发生任何事情。
动作创建者和操作都必须 dispatch()
ed。
- 操作必须被分派,因为它的内部函数就是这样传递给
dispatch
函数变量的,后者又用来分派操作。 - 必须调度操作,因为它们没有自己的功能;它们只是简单的对象。只有当它们被分派到 Redux store 时,它们才会影响 store 状态。
看起来你的这段代码正在调用一个动作创建者而不是调度它:
showLoginModal(false);
将其更改为
dispatch(showLoginModal(false));
可能会解决您的问题。
以一种有助于阅读代码的任何人(包括您)see/remember他们只是创建了一个动作的方式来命名动作创建者可能会有所帮助。例如,您可以将 showLoginModal
重命名为 showLoginModalAction
甚至 createShowLoginModalAction
.
logInUser()
函数是一个操作(因为它调度了一个动作),没有明确的原因,return 也是一个动作。 returns 的操作永远不会发送到商店,至少在发布的代码中是这样,所以它不会有任何效果。可能您的意图是将该操作发送到商店,那么为什么不直接发送它呢?
logInUser(){
dispatch( sendingLoginRequestAction() );
someAsyncLoginFuncThatReturnsAPromise(userName, password)
.then(result=>{
dispatch( loginSucceededAction(result) );
dispatch( hideLoginModalAction() );
});
}
那些动作创作者看起来像:
sendingLoginRequestAction() { return { type: UPDATE_SENDING_LOGIN_REQUEST }; } // You don't have anything like this, but it could be used to show a Waiting animation
loginSucceededAction() { return { type: UPDATE_USER_LOGGED_IN, payload: true }; }
hideDialogModalAction { return { type: UPDATE_LOGIN_MODAL_VISIBLE, payload: false }; }
有帮助吗?