React + Redux:组件不更新

IT技术 javascript reactjs redux
2021-05-26 03:55:52

尝试 React + Redux,并且可能正在做一些明显愚蠢的事情,因为在获取数据时触发操作以通过网络获取数据的组件不会更新(重新渲染)。

这是我的代码的相关部分:

作为应用程序入口点的顶级 index.js:

import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware } from 'redux';
import { Router, browserHistory } from 'react-router';
import reduxPromise from 'redux-promise';
import createLogger from 'redux-logger';

const logger = createLogger();

import routes from './routes';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware(reduxPromise, logger)(createStore);

ReactDOM.render(
  <Provider store={createStoreWithMiddleware(reducers)}>
    <Router history={browserHistory} routes={routes} />
  </Provider>
  , document.querySelector('.container'));

顶级容器应用:

import React, {Component} from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import * as Actions from '../actions';
import Header from '../components/header';
import Showcase from '../components/showcase';

function mapStateToProps(state) {
  return {
    resources: state.resources
  }
}

function mapDispatchToProps(dispatch) {
  return {
    fetchResources: () => {
      dispatch(Actions.fetchResources());
    }
  }
}


class App extends Component {

  render() {
    console.log('props in App', this.props);
    return (
      <div>
        <Header/>
        <Showcase
          fetchResources={this.props.fetchResources}
          resources={this.props.resources}
        />
      </div>
    );
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(App)

在即将挂载时触发操作以发送数据请求并应该显示获取的数据的组件:

import React, {Component} from 'react';
import {connect} from 'react-redux';

class Showcase extends Component {
  constructor(props) {
    super(props);
  }

  componentWillMount() {
    this.props.fetchResources();
  }

  render() {
    console.log('resources', this.props);
    return (
      <div>
        This is showcase
      </div>
    );
  }
}

export default connect(state => ({resources: state.resources}))(Showcase)

动作创作者:

import * as types from '../constants/ActionTypes';
import axios from 'axios';

export function fetchResources() {
  return {
    type: types.FETCH_FIRST,
    payload: axios.get('/sampledata/1.json')
  }
}

提取操作的减速器:

import * as types from '../constants/ActionTypes';

export default function resourcesReducer (state={}, action) {
  switch (action.type) {
    case types.FETCH_FIRST:
      console.log('about to return', Object.assign (state, {resources: action.payload.data }))
      return Object.assign (state, {resources: action.payload.data });
    default:
      return state
  }
};

最后是根减速器:

import { combineReducers } from 'redux';
import navigationReducer from './navigation-reducer';
import resourcesReducer from './resources-reducer';

const rootReducer = combineReducers({
  navigationReducer,
  resourcesReducer
});

export default rootReducer;

所以,这就是我正在观察的。请求数据的动作被成功触发,一个请求被发送,reducer 在 promise 被解析时接收它,并用获取的数据更新状态。此时,我希望顶级App组件和Showcase组件检测到商店已更新,并重新渲染,但我没有在控制台中看到它。

另外,我redux-logger对 的控制台输出感到困惑

在此处输入图片说明

具体来说,我很惊讶地看到state包含来自 rootReducer 的减速器——我不知道它是否正确(Redux logger Github 页面上的一个例子显示了没有减速器的状态)。prev state报告asredux-logger包含与 相同的resourcesReducer对象似乎也令人惊讶next state,尽管直觉上我预计prev state或多或少是空的。

您能否指出我做错了什么以及如何让 React 组件响应state更改?

==================================================

更新:

1) 更改组件中mapStateToProps功能App,使其正确映射到减速器状态:

function mapStateToProps(state) {
  return {
    resources: state.resourcesReducer
  }
}

2) 仍然resources向下传递给`Showcase 组件:

  render() {
    console.log('props in App', this.props);
    return (
      <div>
        <Header navigateActions={this.props.navigateActions}/>
        React simple starter
        <Showcase
          fetchResources={this.props.fetchResources}
          resources={this.props.resources}
        />
      </div>
    );

3) 尝试resources通过将其字符串化以查看此对象内部的实际内容来在屏幕上显示

  render() {
    console.log('resources', this.props);
    return (
      <div>
        This is showcase {JSON.stringify(this.props.resources)}
      </div>
    );
  }

在屏幕上看到这个:This is showcase {}该组件似乎没有重新渲染。

这是控制台的屏幕截图,显示 App 的props已更新为next state. 尽管如此,这并没有导致组件重新渲染:

在此处输入图片说明

再次更新:我的 javascript-fu 也很差。我并没有完全意识到通过返回Object.assign (state, {resources: action.payload.data });我实际上是在改变状态,并且一个简单的参数倒置可以让我实现我的意图。感谢这个关于 SO 的讨论的启发。

1个回答

我很惊讶地看到状态包含来自 rootReducer 的 reducer

这就是它的工作原理。仔细看看combineReducers()

const rootReducer = combineReducers({
  navigationReducer,
  resourcesReducer
});

认识到它不是参数列表;它是一个单一的对象参数。也许在详细语法中更清楚:

var rootReducer = combineReducers({
  navigationReducer: navigationReducer,
  resourcesReducer: resourcesReducer
});

resourcesReducer对国家关键点返回由resourcesReducer()函数。也就是说,里面的state变量resourcesReducer()只是整个状态的一部分。

传递的函数connect()将整个状态作为参数。你的实际应该是这样的:

export default connect(state => ({
  resources: state.resourcesReducer.resources
}))(Showcase);