问题
我在redux(使用redux thunk)中有一个异步函数,它在redux存储区中设置一个值。它在我的应用程序中被多次使用但是,我希望在redux函数运行后使用redux函数设置的新值发生不同的事情。似乎是一个回调的好理由,对吗?所以我尝试这样做,但是我收到了以下错误:
未捕获的TypeError:无法读取未定义的属性“然后”
尝试修复的逻辑
我想到原因可能是虽然redux函数调度了动作,但它实际上并没有返回任何内容。因此,我在redux函数中添加了returns
,认为函数会将某些东西返回给调用它的组件,这将解决我收到的错误。没有运气。
问题:
有没有人知道在异步redux函数(使用redux thunk)运行并完成在redux存储中设置新值后如何执行函数
我最近的尝试解决
组件
import {fetchUser} from './../actions/index.js';
class MyComponent extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
// Attempt #1: this.props.fetchUserData()); // originally I attempted just running one function and then the rest without a callback but the new value was not set in redux store before the next function that needed it ran
// Attempt #2: this.props.fetchUserData().then(function() => { // I also tried running just a standard .then(function()
// Attempt #3: (line below)
this.props.fetchUserData().then((resultFromReduxFunction) => {
console.log("fetchUserData result = " + resultFromReduxFunction);
// do some stuff with the new data
console.log("this.props.reduxData.userHairColor = " + this.props.reduxData.userHairColor);
console.log("this.props.reduxData.userHeight = " + this.props.reduxData.userHeight);
});
}
}
function mapStateToProps(state) {
return {
reduxData: state.user
};
}
function matchDispatchToProps(dispatch) {
return bindActionCreators({
fetchUserData: fetchUserData
}, dispatch)
}
export default connect(mapStateToProps, matchDispatchToProps)(MyComponent);
行动创作者
export const set = (idToSet, payloadToSet) => {
return {
type: 'SET',
id: idToSet,
payload: payloadToSet
}
}
export const fetchUserData = (callbackFunction) => {
console.log("fetchUserData triggered...");
return (dispatch, getState) => {
firebase.auth().onAuthStateChanged(function (user) {
if (!user) {
console.log("no user logged in");
return false // Added in attempt to fix callback
} else {
// fetch some more user data
firebase.database().ref().child('users').child(user.uid).on('value', function(snapshot) {
var userHairColor = snapshot.child(userHairColor).val();
var userHeight = snapshot.child(userHeight).val();
dispatch(set('userHairColor', userHairColor));
dispatch(set('userHeight', userHeight));
return true // Added in attempt to fix callback
})
}
})
}
}
Redux商店
const initialState = {
userHairColor: "",
userHeight: ""
}
export default function (state=initialState, action) {
switch(action.type) {
case 'SET':
return {
...state,
[action.id]: action.payload
}
default:
return {
...state
}
}
}
提前感谢您提供任何帮助
答案 0 :(得分:1)
如果你真的在thunk中明确地调用它,回调会起作用,但它真的感觉像是一个反模式。
相反,你可以派遣另一个可以处理任何进一步逻辑的thunk。
export const fetchUserData = (callbackFunction) => {
console.log("fetchUserData triggered...");
return (dispatch, getState) => {
firebase.auth().onAuthStateChanged(function (user) {
...do stuf...
dispatch(doMoreStuff())
})
}
}
或者,如果您需要对react组件内部的结果做出反应,则会调度将修改redux状态的操作。这将反过来调用反应生命周期方法和render
,您可以根据新状态对那里的变化做出反应。
为了改善答案,有助于在行动完成后知道您想要做什么。
答案 1 :(得分:1)
要使用.then(...)
,你的thunk必须返回一个Promise。 Firebase的onAuthStateChanged
似乎返回取消订阅功能,而不是Promise,因此即使您返回该功能,也不允许您在您的动作创建者呼叫网站上链接其他回调。并且您无法从传递给onAuthStateChanged
的回调中返回,因为您在此时处于不同的调用堆栈中(它是异步的)。
您需要做的是将回调函数传递给您的动作创建者,它需要在数据提取的成功回调中调用。
这样的事情:
export const fetchUserData = (callbackFunction) => {
return (dispatch, getState) => {
firebase.auth().onAuthStateChanged(function (user) {
if (!user) {
console.log("no user logged in");
// You can pass false to your callback here, so that it knows the auth was unsuccessful
callbackFunction(false);
} else {
// fetch some more user data
firebase.database().ref().child('users').child(user.uid).on('value', function(snapshot) {
var userHairColor = snapshot.child(userHairColor).val();
var userHeight = snapshot.child(userHeight).val();
dispatch(set('userHairColor', userHairColor));
dispatch(set('userHeight', userHeight));
// Passing true so your callback knows it was a success
callbackFunction(true);
})
}
})
}
}
然后根据需要使用它:
this.props.fetchUserData((success) => {
console.log("fetchUserData result = " + success);
// do some stuff with the new data
console.log("this.props.reduxData.userHairColor = " + this.props.reduxData.userHairColor);
console.log("this.props.reduxData.userHeight = " + this.props.reduxData.userHeight);
});
这里有一些回调地狱,但为了避免这种情况,你必须使用" promisified" Firebase的API版本,在这种情况下,您也可以从thunk返回承诺,以便使用您的操作创建者的任何内容都可以附加.then(...)
。