反应组件状态不更新(FLUX App)
react component state not updating (FLUX App)
我正在尝试手动构建一个 react/flux 应用程序,大致如下:
https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture
我已经完成了大部分工作,但是当我更新状态时,组件不会重新呈现。有人可以帮忙吗?
谢谢。 :)
回购是 https://github.com/jmsherry/flux_hand
CounterStore.js
import Dispatcher from 'Flux';
import AppDispatcher from './../dispatcher/AppDispatcher';
import CounterConstants from '../constants/constants';
import { EventEmitter } from 'events';
import assign from 'object-assign';
let _count = 5;
function increment() {
_count +=1;
}
function decrement() {
_count -=1;
}
let CounterStore = assign({}, EventEmitter.prototype, {
getCount() {
return _count;
},
emitChange() {
this.emit(CounterConstants.CHANGE_EVENT);
},
/**
* @param {function} callback
*/
addChangeListener(callback) {
this.on(CounterConstants.CHANGE_EVENT, callback);
},
/**
* @param {function} callback
*/
removeChangeListener(callback) {
this.removeListener(CounterConstants.CHANGE_EVENT, callback);
},
dispatcherIndex: AppDispatcher.register(function(payload) {
console.log('blah', arguments);
var action = payload.action;
var text;
switch(action.actionType) {
case CounterConstants.INCREMENT:
console.log('inc', _count);
increment();
console.log(_count);
CounterStore.emitChange();
break;
case CounterConstants.DECREMENT:
console.log('dec', _count);
decrement();
console.log(_count);
CounterStore.emitChange();
break;
}
return true; // No errors. Needed by promise in Dispatcher.
})
});
export default CounterStore;
AppDispatcher.js
import { Dispatcher } from 'Flux';
const AppDispatcher = new Dispatcher();
AppDispatcher.handleViewAction = function(action) {
console.log('in', arguments);
this.dispatch({
source: 'VIEW_ACTION',
action
});
}
export default AppDispatcher;
constants.js
import keyMirror from 'keymirror';
const CounterConstants = keyMirror({
INCREMENT: null,
DECREMENT: null
});
CounterConstants.CHANGE_EVENT = 'change';
export default CounterConstants;
actions.js
import AppDispatcher from '../dispatcher/AppDispatcher';
var CounterConstants = require('../constants/constants');
const CounterActions = {
/**
* @param {string} text
*/
increment() {
AppDispatcher.handleViewAction({
actionType: CounterConstants.INCREMENT
});
},
decrement() {
AppDispatcher.handleViewAction({
actionType: TodoConstants.DECREMENT
});
}
};
export default CounterActions;
counter.js <-- 父视图
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import CounterConstants from './../constants/constants';
import AppDispatcher from './../Dispatcher/AppDispatcher.js';
import Controls from './Controls';
import Display from './Display';
class Counter extends Component {
render(){
return (
<div className="counter">
<h1>My counter</h1>
<Display />
<Controls />
</div>
)
}
}
export default Counter;
controls.js
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import CounterConstants from './../constants/constants';
import AppDispatcher from './../dispatcher/AppDispatcher';
import CounterActions from './../actions/actions';
class Controls extends Component {
render(){
console.log('here', AppDispatcher);
return (
<div className="controls">
<button onClick={CounterActions.increment}>+</button>
<button onClick={CounterActions.decrement}>-</button>
</div>
)
}
}
export default Controls;
display.js
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import CounterConstants from './../constants/constants';
import CounterStore from './../stores/CounterStore';
// Method to retrieve application state from store
function getAppState() {
console.log('getting app state...');
return {
count: CounterStore.getCount()
};
}
class Display extends Component {
constructor(props) {
super(props);
this.state = getAppState();
}
// Update view state when change event is received
_onChange() {
console.log('prechange', this.state);
const newState = getAppState();
console.log('newState', newState);
(newState) => this.setState;
}
// Listen for changes
componentDidMount() {
CounterStore.addChangeListener(this._onChange.bind(this));
}
// Unbind change listener
componentWillUnmount() {
CounterStore.removeChangeListener(this._onChange.bind(this));
}
shouldComponentUpdate( newProps, newState ) {
console.log('shouldComponentUpdate', arguments);
}
render() {
let count = getAppState().count;
console.log('rendering', count, this.state);
return (
<div className = "display" >
<p>State: { this.state.count }</p>
<p>count: { count }</p>
</div>
)
}
}
export default Display;
除非我在你的代码中遗漏了什么,否则你不会在任何地方调用 setState
来更新你的状态,这是 React 中更新状态并强制重新渲染的惯用方式。
您的 _onChange
方法应该使用新状态调用 setState
,组件将自动重新呈现。
更多阅读在这里:
所以看起来好像您在匿名函数的括号中调用 setState,而实际上您可以在 _onChange
方法中使用 this
调用它。
尝试改变这个
(newState) => this.setState;
对此:
this.setState(newState);
编辑:
您可能必须在 Display 构造函数中包含对此的绑定,如下所示:
constructor(props) {
super(props);
this.state = getAppState();
this._onChange = this._onChange.bind(this);
}
好的!所以,我遇到了 this
绑定的问题,所以我使用了 es6 箭头函数。我是 es6 的一些新手,我在那里得到的是行不通的。这不是你执行箭头函数的方式,这就是它不起作用的原因......
我正在尝试手动构建一个 react/flux 应用程序,大致如下: https://scotch.io/tutorials/getting-to-know-flux-the-react-js-architecture
我已经完成了大部分工作,但是当我更新状态时,组件不会重新呈现。有人可以帮忙吗?
谢谢。 :)
回购是 https://github.com/jmsherry/flux_hand
CounterStore.js
import Dispatcher from 'Flux';
import AppDispatcher from './../dispatcher/AppDispatcher';
import CounterConstants from '../constants/constants';
import { EventEmitter } from 'events';
import assign from 'object-assign';
let _count = 5;
function increment() {
_count +=1;
}
function decrement() {
_count -=1;
}
let CounterStore = assign({}, EventEmitter.prototype, {
getCount() {
return _count;
},
emitChange() {
this.emit(CounterConstants.CHANGE_EVENT);
},
/**
* @param {function} callback
*/
addChangeListener(callback) {
this.on(CounterConstants.CHANGE_EVENT, callback);
},
/**
* @param {function} callback
*/
removeChangeListener(callback) {
this.removeListener(CounterConstants.CHANGE_EVENT, callback);
},
dispatcherIndex: AppDispatcher.register(function(payload) {
console.log('blah', arguments);
var action = payload.action;
var text;
switch(action.actionType) {
case CounterConstants.INCREMENT:
console.log('inc', _count);
increment();
console.log(_count);
CounterStore.emitChange();
break;
case CounterConstants.DECREMENT:
console.log('dec', _count);
decrement();
console.log(_count);
CounterStore.emitChange();
break;
}
return true; // No errors. Needed by promise in Dispatcher.
})
});
export default CounterStore;
AppDispatcher.js
import { Dispatcher } from 'Flux';
const AppDispatcher = new Dispatcher();
AppDispatcher.handleViewAction = function(action) {
console.log('in', arguments);
this.dispatch({
source: 'VIEW_ACTION',
action
});
}
export default AppDispatcher;
constants.js
import keyMirror from 'keymirror';
const CounterConstants = keyMirror({
INCREMENT: null,
DECREMENT: null
});
CounterConstants.CHANGE_EVENT = 'change';
export default CounterConstants;
actions.js
import AppDispatcher from '../dispatcher/AppDispatcher';
var CounterConstants = require('../constants/constants');
const CounterActions = {
/**
* @param {string} text
*/
increment() {
AppDispatcher.handleViewAction({
actionType: CounterConstants.INCREMENT
});
},
decrement() {
AppDispatcher.handleViewAction({
actionType: TodoConstants.DECREMENT
});
}
};
export default CounterActions;
counter.js <-- 父视图
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import CounterConstants from './../constants/constants';
import AppDispatcher from './../Dispatcher/AppDispatcher.js';
import Controls from './Controls';
import Display from './Display';
class Counter extends Component {
render(){
return (
<div className="counter">
<h1>My counter</h1>
<Display />
<Controls />
</div>
)
}
}
export default Counter;
controls.js
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import CounterConstants from './../constants/constants';
import AppDispatcher from './../dispatcher/AppDispatcher';
import CounterActions from './../actions/actions';
class Controls extends Component {
render(){
console.log('here', AppDispatcher);
return (
<div className="controls">
<button onClick={CounterActions.increment}>+</button>
<button onClick={CounterActions.decrement}>-</button>
</div>
)
}
}
export default Controls;
display.js
import React,{Component} from 'react';
import ReactDOM from 'react-dom';
import CounterConstants from './../constants/constants';
import CounterStore from './../stores/CounterStore';
// Method to retrieve application state from store
function getAppState() {
console.log('getting app state...');
return {
count: CounterStore.getCount()
};
}
class Display extends Component {
constructor(props) {
super(props);
this.state = getAppState();
}
// Update view state when change event is received
_onChange() {
console.log('prechange', this.state);
const newState = getAppState();
console.log('newState', newState);
(newState) => this.setState;
}
// Listen for changes
componentDidMount() {
CounterStore.addChangeListener(this._onChange.bind(this));
}
// Unbind change listener
componentWillUnmount() {
CounterStore.removeChangeListener(this._onChange.bind(this));
}
shouldComponentUpdate( newProps, newState ) {
console.log('shouldComponentUpdate', arguments);
}
render() {
let count = getAppState().count;
console.log('rendering', count, this.state);
return (
<div className = "display" >
<p>State: { this.state.count }</p>
<p>count: { count }</p>
</div>
)
}
}
export default Display;
除非我在你的代码中遗漏了什么,否则你不会在任何地方调用 setState
来更新你的状态,这是 React 中更新状态并强制重新渲染的惯用方式。
您的 _onChange
方法应该使用新状态调用 setState
,组件将自动重新呈现。
更多阅读在这里:
所以看起来好像您在匿名函数的括号中调用 setState,而实际上您可以在 _onChange
方法中使用 this
调用它。
尝试改变这个
(newState) => this.setState;
对此:
this.setState(newState);
编辑:
您可能必须在 Display 构造函数中包含对此的绑定,如下所示:
constructor(props) {
super(props);
this.state = getAppState();
this._onChange = this._onChange.bind(this);
}
好的!所以,我遇到了 this
绑定的问题,所以我使用了 es6 箭头函数。我是 es6 的一些新手,我在那里得到的是行不通的。这不是你执行箭头函数的方式,这就是它不起作用的原因......