繁体   English   中英

Redux Thunk函数后的回调:未捕获的TypeError:无法读取未定义的属性'then'

[英]Callback after Redux Thunk function: Uncaught TypeError: Cannot read property 'then' of undefined

问题

我在redux(带有redux thunk)中有一个异步函数,该函数在redux存储中设置一个值。 在我的应用程序中,它多次使用,但是,我希望在使用redux函数设置的新值运行redux函数之后发生不同的事情。 似乎是进行回调的充分理由,对吧? 所以我尝试这样做,但是出现以下错误:

Uncaught TypeError:无法读取未定义的属性“ then”

尝试修复的逻辑

认为原因可能是尽管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
      }
  }
}

预先感谢您的任何帮助

如果您实际上在thunk中显式调用了回调,则该回调将起作用,但实际上感觉像是一种反模式。

相反,您可以调度另一个可以处理任何进一步逻辑的重击。

export const fetchUserData = (callbackFunction) => {
  console.log("fetchUserData triggered...");
  return (dispatch, getState) => {
    firebase.auth().onAuthStateChanged(function (user) {
      ...do stuf...
      dispatch(doMoreStuff())
    })
  }
}

或者,如果您需要对React组件中的结果做出反应,请分派一个将修改您的Redux状态的操作。 这将依次调用react生命周期方法并进行render ,您可以根据新状态对那里的更改做出反应。

要改善答案,这将有助于您在完成操作后知道要执行的操作。

要使用.then(...) ,您的thunk必须返回一个Promise。 Firebase的onAuthStateChanged似乎返回一个退订函数,而不是Promise,因此即使您返回了它,它也不允许您在操作创建者调用站点上链接其他回调。 而且您无法从传递给onAuthStateChanged的回调中返回,因为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);
});

这里有一些回调地狱,但是为了避免您必须使用Firebase API的“承诺版本”,在这种情况下,您还可以从thunk中返回promise,以便使用动作创建者的任何东西都可以附加一个.then(...)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM