2017-06-17 39 views
0

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

我做了什么

我读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减速和行动创造者:

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 

这里是我结合减速器的地方:

import { combineReducers } from 'redux' 

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

这里是显示我的控制台的屏幕截图。 (我不是很了解这个跨框架的原点错误,并且会欢迎一个解释,但我认为这是我的问题的辅助,因为我通过它并成功通过减速器传递行动。)enter image description here

我成功在第一个渲染器的控制台日志标签中,但是在状态上设置标签后没有重新渲染,并且我不再控制日志标签(或渲染页面上的标签列表)。

感谢您提供任何帮助!

p.s.而且,为了完整起见,这里是我在做异步gmail API的东西。 (我知道我现在没有遵循异步动作创建者的格式,我正在处理来自gmail api的示例代码,我只是想先弄清楚并运行,然后展开并清理我的代码。 “T认为问题都不可能在这里是因为状态被填充的罚款;我只是不能重新解析页面)

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

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

您有:

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

这样,你将被出口连接的组件。

+0

我敢肯定你是对的,我没有upvoted并接受你的答案的唯一原因是,现在由于某种原因连接到gmail api不工作,我没有得到标签更新因此我无法验证您的建议是否可以解决任何问题。我试图弄清楚什么是错误的,以及更新我的问题还是提出一个新问题是否合适。 – Katie

+0

是的,我不是那个api如何工作的。另外,如果您使用的是redux,则不需要本地状态。也许一个解决问题的好方法是摆脱redux,并尝试使其与反应组件中的本地状态一起工作,然后将功能分解为redux。 –

+0

我修好了。我只需要调用fetchLabels()作为.signIn()的关闭。我认为之前没有造成麻烦的唯一原因是我的登录状态持续存在于浏览器中,因此总有一位fetchLabel用户可以找到。我会接受你的回答。谢谢你的帮助! – Katie

相关问题