【发布时间】:2017-11-20 10:21:42
【问题描述】:
我正在尝试编写一个简单的测试 react-redux 应用程序来开始使用 gmail API,现在状态更改不会强制重新渲染。
我做了什么:
我读过this question。那个人的问题似乎不是由connect-ing 组件引起的,但据我所知,我正在这样做。我读了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
这里是我结合减速器的地方:
import { combineReducers } from 'redux'
const rootReducer = combineReducers({
auth: require('./auth').default,
gmail: require('./gmail').default
})
export default rootReducer
这是显示我的控制台的屏幕截图。 (我不太了解这个跨框架起源错误,欢迎解释,但我认为这是我的问题的辅助,因为我克服了它并成功通过减速器传递了一个动作。)
我在第一次渲染时成功地控制台记录标签,但是在状态上设置标签后没有重新渲染,并且我不再控制台日志标签(或在页面上渲染标签列表)。
感谢您提供的任何帮助!
附言而且,为了完整起见,这里是我做异步 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))
})
}
【问题讨论】:
标签: reactjs redux react-redux