Redux reducer 不更新 store/redux-promise 不解决

Posted

技术标签:

【中文标题】Redux reducer 不更新 store/redux-promise 不解决【英文标题】:Redux reducer doesn't update store/redux-promise not resolving 【发布时间】:2018-08-09 21:19:09 【问题描述】:

所以我最近开始学习 Redux,现在我正在尝试用它制作我的第一个应用程序,但我偶然发现了一个我无法自己解决的问题。基本上我希望用户单击一个按钮(将进行身份验证)并从 Firebase 获取他或她的所有数据并显示它。

这是我的 index.js:

// Dependencies
import React from 'react';
import ReactDOM from 'react-dom';
import  Provider  from 'react-redux';
import  createStore, applyMiddleware, combineReducers  from 'redux';
import createHistory from 'history/createBrowserHistory';
import  ConnectedRouter, routerReducer, routerMiddleware  from 'react-router-redux';
import ReduxPromise from "redux-promise";
import ReduxThunk from 'redux-thunk';

// Reducers
import rootReducer from './reducers';

// ServiceWorker
import registerServiceWorker from './registerServiceWorker.js';

// Styles
import './styles/index.css';

// Components
import App from './containers/App.js';

const history = createHistory();

const middleware = routerMiddleware(history);

// Create store
const store = createStore(
  combineReducers(
    ...rootReducer,
    router: routerReducer
  ),
  applyMiddleware(ReduxThunk, middleware, ReduxPromise)
)

ReactDOM.render((
  <Provider store=store>
    <ConnectedRouter history=history>
      <App />
    </ConnectedRouter>
  </Provider>
), document.getElementById('root'));

registerServiceWorker();

还有我的主容器 App.js:

import React,  Component  from 'react';
import  Route, Switch, withRouter  from 'react-router-dom'
import  connect  from 'react-redux';
import  bindActionCreators  from 'redux';
import firebase from 'firebase';

import firebaseConfig from '../firebaseConfig.js';

// Actions
import  fetchAllMonths  from "../actions/index";

// Static components
import Nav from '../components/Nav.js';

// Routes
import CurrentMonth from '../components/CurrentMonth.js';
import AddNewMonth from '../components/AddNewMonth.js';
import Archive from '../components/Archive.js';
import Settings from '../components/Settings.js';

class App extends Component 
  constructor (props) 
    super(props);

    this.login = this.login.bind(this);
  

  componentWillMount() 
    firebase.initializeApp(firebaseConfig);
    firebase.auth().signInAnonymously().catch(function(error) 
      var errorCode = error.code;
      var errorMessage = error.message;
    );
  

  login() 
    this.props.fetchAllMonths();
  

  render() 
    if (this.props.data === undefined) 
      return (
        <button onClick=this.login>Login</button>
      )
     else if (this.props.data !== undefined) 
      return (
        <main className="main-container">
          <Nav user="user"/>
          <Switch>
            <Route exact path='/' component=CurrentMonth/>
            <Route path='/aktualny' component=CurrentMonth/>
            <Route path='/nowy' component=AddNewMonth/>
            <Route path='/archiwum' component=Archive/>
            <Route path='/ustawienia' component=Settings/>
          </Switch>
        </main>
    );
    
  


function mapDispatchToProps(dispatch) 
  return bindActionCreators( fetchAllMonths , dispatch);


function mapStateToProps( data ) 
  return  data ;


export default withRouter(connect(mapStateToProps, mapDispatchToProps)(App))

主要操作,fetchAllMonths:

// import firebase from 'firebase';
// Firebase Config
// import axios from 'axios';

export const FETCH_ALL_MONTHS = 'FETCH_ALL_MONTHS';

export function fetchAllMonths() 
  /*const database = firebase.database();
  const data = database.ref('/users/grhu').on('value', function(snapshot) 
    return snapshot.val();
  );

  console.log(data) */

  const data = fetch('https://my-finances-app-ef6dc.firebaseio.com/users/grhu.json')
    .then(async (response) => response.json())
    .then(data => 
        console.log(data);
        return data;
      
    )

  console.log(data);

  return 
    type: FETCH_ALL_MONTHS,
    payload: data
  ;
;

减速器 index.js:

import  combineReducers  from "redux";
import data from "./reducer_load_from_db";

const rootReducer = combineReducers(
  data: data
);

export default rootReducer;

最后是我的减速器:

import  FETCH_ALL_MONTHS  from "../actions/index";

export default function(state = [], action) 
  switch (action.type) 
    case FETCH_ALL_MONTHS:
      return [action.payload.data, ...state];
    default:
      return state;
  
  return state;

所以我确信 fetch 可以正常工作,因为 console.log(data) 给了我一个有效的 JSON 文件,但是带有传递的 const 的第二个 console.log(data) 给了我一个承诺,然后我将它作为有效载荷到减速器。 CreateStore 似乎也可以工作,因为在 React 开发控制台中,我可以在 App 容器中看到一个“数据”道具。我使用 redux-promise 应该解析有效负载中的 Promise 并将 JSON 返回到存储,但数据仍然未定义。还尝试了 redux-promise-middleware,但同样没有运气。

我错过了什么?我已经看了几个小时的代码,我不明白它有什么问题。

我会感谢所有答案,但我真的很想了解这个问题,而不仅仅是复制粘贴解决方案。

提前致谢!

【问题讨论】:

but data remains undefined. 这是来自你的 redux 状态吗?那么你应该return ...state, data: action.payload.data ; 所以数据状态将保存你的有效负载数据。 或者如果你喜欢return ...state, ...action.payload 不幸的是,这并没有改变任何事情。我还向减速器添加了console.logs,但看起来它甚至没有达到它 - 我仍然只看到两个 console.logs 来自操作(第 18 行和第 23 行)。 我看到的还有一件事是,在你的减速器上你使用动作。在使用 const 的组件上。如果你检查一下可能值得 【参考方案1】:

初步回答

根据我在您的fetchAllMonths() 操作创建器中阅读的内容,您正在为其返回的操作设置一个属性,称为payload 等于 从您的 API 调用返回的数据。

  return 
    type: FETCH_ALL_MONTHS,
    payload: data
  ;

如果您像这样在减速器中记录action.payload...

  switch (action.type) 
    case FETCH_ALL_MONTHS:
      console.log(action.payload)
      return [action.payload.data, ...state];
    default:
      return state;
  

我相信您会看到您的 API 调用返回的数据。

因此,在您的减速器中,您会期望 action.payload 作为 FETCH_ALL_MONTHS 操作的属性。你会想使用扩展运算符...action.payload

另外,为了让您的逻辑更易于阅读,为什么不尝试使用异步操作来获取数据,然后分派一个操作来接收从 API 调用返回的数据?

希望有帮助!

更新答案

当我想到这一点并阅读了您对我的回答的回复时,我认为您可能需要使用异步操作来确保成功获取您的数据。我使用异步操作制作了一个非常简单的 CodePen 示例。

https://codepen.io/joehdodd/pen/rJRbZG?editors=0010

让我知道这是否有帮助,如果你让它以这种方式工作。

【讨论】:

不幸的是,这并没有改变任何事情。我还在减速器中添加了console.logs,但看起来它甚至没有达到它——我仍然只看到两个console.logs 来自操作(第 18 行和第 23 行)。我将如何使用异步创建它? @grhu 我更新了我的答案。在考虑了更多之后,我相信正在发生的事情是不允许 Redux 在尝试触发减速器、设置状态并将其发送到 React 组件之前等待 API 的响应。使用异步操作,就像在我的 CodePen 示例中一样,我相信它会解决您的问题。告诉我!

以上是关于Redux reducer 不更新 store/redux-promise 不解决的主要内容,如果未能解决你的问题,请参考以下文章

redux reducer 不更新 store 中的状态

Redux:重用reducer来更新多个状态属性

Redux:Reducers

在 React/Redux reducer 中,如何以不可变的方式更新嵌套数组中的字符串?

Redux 开发工具状态图显示reducer 正在更新另一个reducer

Reducer 状态没有被新对象更新 [redux, redux-toolkit, normalize]