连接的react-redux组件不会在状态

时间:2017-06-17 21:35:34

标签: reactjs redux react-redux

我正在尝试编写一个简单的测试react-redux应用程序来开始使用gmail API,现在状态更改不会强制重新呈现。

我做了什么

我读了this question。这个人的问题似乎是由connect组件引起的,但据我所知,我正在这样做。我看了this question。那个人的问题是由误解combineReducers如何设置状态对象造成的,但我不认为我有同样的误解。我确定我还有其他一个!

这是我的顶级容器,路由:

'use strict'
import React from 'react'
import {Router, Route, IndexRedirect, browserHistory} from 'react-router'
import {render} from 'react-dom'
import {connect, Provider} from 'react-redux'

import store from './store'
import Home from './components/Home'
import Login from './components/Login'
import WhoAmI from './components/WhoAmI'
import NotFound from './components/NotFound'
import { handleClientLoad } from './gmailApi'

const ExampleApp = connect(
  ({ auth }) => ({ user: auth })
)(
  ({ user, children }) =>
    <div>
      <nav>
        {user ? <WhoAmI/> : <Login/>}
      </nav>
      {children}
    </div>
)

const onAppEnter = () => {
  handleClientLoad()
}

render(
  <Provider store={store}>
    <Router history={browserHistory}>
      <Route path="/" component={ExampleApp}>
        <IndexRedirect to="/home" />
        <Route path="/home" component={Home} onEnter={onAppEnter} />
      </Route>
      <Route path='*' component={NotFound} />
    </Router>
  </Provider>,
  document.getElementById('main')
)

这是我渲染组件的代码:

import React, { Component } from 'react'
import { handleAuthClick, handleSignOutClick } from '../gmailApi'
import store from '../store'
import { connect } from 'react-redux'


var authorizeButton = <button id="authorize-button" onClick={() => { handleAuthClick() }}>Authorize</button>
var signOutButton = <button id="signout-button" onClick={handleSignOutClick}>Sign Out</button>


const mapStateToProps = (state) => {
  return {
    labels: state.gmail.labels,
    isSignedIn: state.gmail.isSignedIn
  }
}

export const Labels = ({ isSignedIn, labels }) => {
  var button = isSignedIn ? signOutButton : authorizeButton
  console.log("labels ", labels)
  return (
    <div>
      {button}
      <ul>
        {labels && labels.map(label => <li>{label}</li>)}
      </ul>
    </div>
  )
}

export default class Home extends Component {

  constructor(props) {
    super(props)

    this.state = {labels: [], isSignedIn: false}
  }

  render() {
    return (
        <Labels labels={this.props.labels} isSignedIn={this.props.isSignedIn}/>
    )
  }

}

connect(mapStateToProps)(Home)

这是我的gmail reducer和action creators:

let initialState = {
    labels: [],
    isSignedIn: false
}

const reducer = (state=initialState, action) => {
    const newState = Object.assign({}, state);
  switch (action.type) {
  case SIGNED_IN:
    newState.isSignedIn = action.isSignedIn
    return newState
  case RECEIVE_LABELS:
    newState.labels = action.labels
    return newState
  }

  return state
}

const SIGNED_IN = 'SIGNED_IN'
export const signedIn = isSignedIn => ({
  type: SIGNED_IN, isSignedIn
})


const RECEIVE_LABELS = 'LABELS'
export const receiveLabels = labels => ({
    type: RECEIVE_LABELS, labels
})


export default reducer

这是我合并reducer的地方:

import { combineReducers } from 'redux'

const rootReducer = combineReducers({
  auth: require('./auth').default, 
  gmail: require('./gmail').default
})
export default rootReducer

这是显示我的控制台的屏幕截图。 (我真的不明白这个跨框架原点错误,并欢迎解释,但我认为它是我的问题的辅助,因为我越过它并成功通过reducer传递一个动作。)enter image description here

我在第一次渲染时成功登录控制台日志标签,但在状态上设置标签后没有重新渲染,我不再控制日志标签(或渲染页面上的标签列表)。

感谢您提供的任何帮助!

P.S。而且,为了完整性,这里是我正在做异步gmail api的东西。 (我知道我现在没有遵循异步动作创建者的格式。我正在使用gmail api中的示例代码,我只是尝试先启动并运行,然后展开并清理我的代码。我不知道我认为问题可能在这里,因为状态变得很好;我只是无法重新呈现页面。)

import store from '../store'
import { signedIn, receiveLabels } from '../reducers/gmail'
import gapi from './gapi'
import '../store'

var CLIENT_ID = '<stack overflow doesn't need to know this>';

// Array of API discovery doc URLs for APIs used by the quickstart
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];

// Authorization scopes required by the API; multiple scopes can be
// included, separated by spaces.
var SCOPES = "https://www.googleapis.com/auth/gmail.modify";


/**
 *  On load, called to load the auth2 library and API client library.
 */


export const handleClientLoad = function() {
    gapi.load('client:auth2', initClient);
}

/**
 *  Initializes the API client library and sets up sign-in state
 *  listeners.
 */
function initClient() {
    gapi.client.init({
        discoveryDocs: DISCOVERY_DOCS,
        clientId: CLIENT_ID,
        scope: SCOPES
    }).then(function () {
        // Listen for sign-in state changes.
        gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus)

        // Handle the initial sign-in state.
        updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());


    });
}

function updateSigninStatus(isSignedIn) {

        console.log(isSignedIn)
        store.dispatch(signedIn(isSignedIn))
}

/**
 *  Sign in the user upon button click.
 */
export const handleAuthClick = function(event) {
    console.log("got here")
    gapi.auth2.getAuthInstance().signIn();
    fetchLabels()
}

/**
 *  Sign out the user upon button click.
 */
export const handleSignoutClick = function(event) {
    gapi.auth2.getAuthInstance().signOut();
}

/**
 * Append a pre element to the body containing the given message
 * as its text node. Used to display the results of the API call.
 *
 * @param {string} message Text to be placed in pre element.
 */

/**
 * Print all Labels in the authorized user's inbox. If no labels
 * are found an appropriate message is printed.
 */
function fetchLabels() {
    console.log("gapi client ", gapi.client)
    gapi.client.gmail.users.labels.list({
        'userId': 'me'
    }).then(function (response) {
        var labels = response.result.labels;
        store.dispatch(receiveLabels(labels))
    })
}

1 个答案:

答案 0 :(得分:1)

我看到的错误是您没有导出连接的组件。您导出组件,然后稍后连接它。 connect函数返回一个新的高阶组件;它不会影响组件本身。此外,connect函数采用第二个参数:将动作分派给状态存储的动作创建者。如果您希望将这些操作发送到Reducer,则需要导入这些操作。

你有:

export default class Home extends Component {

  constructor(props) {
    super(props)

    this.state = {labels: [], isSignedIn: false}
  }

  render() {
    return (
        <Labels labels={this.props.labels} isSignedIn={this.props.isSignedIn}/>
    )
  }

}

connect(mapStateToProps)(Home)

只需将其更改为:

import * as actions from './nameOfActionsFolder';

class Home extends Component {

  constructor(props) {
    super(props)

    this.state = {labels: [], isSignedIn: false}
  }

  render() {
    return (
        <Labels labels={this.props.labels} isSignedIn={this.props.isSignedIn}/>
    )
  }

}

export default connect(mapStateToProps, actions)(Home);

这样您就可以导出连接的组件。