2017-06-17 72 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

相關問題