我正在尝试编写一个简单的测试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传递一个动作。)
我在第一次渲染时成功登录控制台日志标签,但在状态上设置标签后没有重新渲染,我不再控制日志标签(或渲染页面上的标签列表)。
感谢您提供的任何帮助!
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))
})
}
答案 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);
这样您就可以导出连接的组件。