简体   繁体   English

React + Redux:组件不更新

[英]React + Redux: Component does not update

Trying out React + Redux, and probably am doing something obviously stupid, because a component that fires an action to fetch data over the network does not get updated (re-rendered) when the data is fetched.尝试 React + Redux,并且可能正在做一些明显愚蠢的事情,因为在获取数据时触发操作以通过网络获取数据的组件不会更新(重新渲染)。

Here are the relevant bits of my code:以下是我的代码的相关部分:

The top-level index.js serving as an entry point for the app:作为应用程序入口点的顶级 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'));

Top-level container App:顶级容器应用:

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)

Component that triggers an action to sends a request for data when it is about to mount and is supposed to show the fetched data:在即将挂载时触发操作以发送数据请求并应该显示获取的数据的组件:

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)

Action Creator:动作创作者:

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

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

Reducer for the fetch action:提取操作的减速器:

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
  }
};

and finally the root reducer:最后是根减速器:

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

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

export default rootReducer;

So, here is what I am observing.所以,这就是我正在观察的。 The action to request data is successfully triggered, a request is sent, the reducer receives it when the promise is resolved, and updates the state with the fetched data.请求数据的动作被成功触发,一个请求被发送,reducer 在 promise 被解析时接收它,并用获取的数据更新状态。 At this point, I would expect the top-level App component and the Showcase component to detect that the store has updated, and to re-render, but I do not see it in the console.此时,我希望顶级App组件和Showcase组件检测到商店已更新并重新渲染,但我在控制台中看不到它。

Also, I am confused by redux-logger 's console output:另外,我对redux-logger的控制台输出感到困惑:

在此处输入图片说明

Specifically, I am surprized to see that the state contains reducers from the rootReducer — I don't know if it's right (an example on Redux logger Github page shows a state without reducers).具体来说,我很惊讶地看到state包含来自 rootReducer 的减速器——我不知道它是否正确( Redux logger Github 页面上的一个例子显示了一个没有减速器的状态)。 It also seems surprising that the prev state as reported by redux-logger contains the same resourcesReducer object as the next state , although intuitively I would expect prev state to be more or less empty.redux-logger报告的prev state包含与next state相同的resourcesReducer对象似乎也令人惊讶,尽管直觉上我希望prev state或多或少是空的。

Could you please point out what I am doing wrong and how to get React components respond to the state changes?您能否指出我做错了什么以及如何让 React 组件响应state变化?

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

UPDATED:更新:

1) Changed the mapStateToProps function in the App component so that it correctly maps to reducer states: 1) 更改了App组件中的mapStateToProps函数,使其正确映射到 reducer 状态:

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

2) Still passing the resources down to the `Showcase component: 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) Trying to display resources on the screen by stringifying it to see what's actually inside this object: 3) 尝试通过字符串化来在屏幕上显示resources以查看该对象内部的实际内容:

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

See this on the screen: This is showcase {} .在屏幕上看到: This is showcase {} The component does not seem to re-render.该组件似乎没有重新渲染。

Here's the screenshot of the console showing that App's props have updated with the values from the next state .这是控制台的屏幕截图,显示 App 的 props 已使用next state的值进行更新。 Still, that did not cause the component to re-render:尽管如此,这并没有导致组件重新渲染:

在此处输入图片说明

UPDATED AGAIN: And my javascript-fu was poor, too.再次更新:我的 javascript-fu 也很差。 I did not quite realize that by returning Object.assign (state, {resources: action.payload.data });我没有完全意识到通过返回Object.assign (state, {resources: action.payload.data }); I was in fact mutating the state, and that a simple inversion of arguments would let me achieve what I intended.我实际上是在改变状态,并且一个简单的参数倒置可以让我实现我的意图。 Thanks to this discussion on SO for enlightenment.感谢这个关于 SO 的讨论的启发。

I am surprized to see that the state contains reducers from the rootReducer我很惊讶地看到状态包含来自 rootReducer 的 reducer

This is how it works.这就是它的工作原理。 Take a closer look at combineReducers() .仔细看看combineReducers()

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

Recognise that it's not a list of parameters;认识到它不是参数列表; it's a single object parameter.它是一个单一的对象参数。 Perhaps it is clearer in verbose syntax:也许在详细语法中更清楚:

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

The resourcesReducer key points to the state returned by the resourcesReducer() function. resourcesReducer键指向resourcesReducer()函数返回的状态。 That is, the state variable within the resourcesReducer() is just one part of the entire state.也就是说, resourcesReducer()state变量只是整个状态的一部分。

The functions passed to connect() take the entire state as an argument.传递给connect()的函数connect()整个状态作为参数。 What yours should actually look like is this:你的实际应该是这样的:

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

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

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