ReactJs + Reflux // trigger 是在 null 组件上执行的?
ReactJs + Reflux // trigger is executed on null component?
我正在尝试在我的 ReactJs 应用程序中使用 Reflux。
我遇到一个问题,侦听数据存储的组件正在空组件实例而不是实例化的实际组件上执行回调。
调用操作 toggleUserBar 后,将调用数据存储并执行触发器。在组件Sidebar中调用了回调但是组件状态为空:
Uncaught TypeError: Cannot read property 'sd' of undefined
知道我做错了什么吗?
actions.tsx
var Reflux = require('reflux');
var RQ = {};
RQ.actions = Reflux.createActions([
"toggleUserBar"
]);
window.RQ = RQ;
store.tsx
RQ.store = Reflux.createStore({
listenables: [RQ.actions],
init: function() {},
onToggleUserBar: function() {
this.trigger();
}
});
sidebar.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";
const LeftNav = require('material-ui/lib/left-nav');
const Menu = require('material-ui/lib/menu/menu')
interface ISidebarProps extends React.Props<any> {
}
interface ISidebarState extends React.Props<any> {
shown: Boolean;
sd: any;
}
export class Sidebar extends React.Component<ISidebarProps, ISidebarState> {
unsubscribe: any;
constructor(props: ISidebarProps) {
super(props);
this.state = { shown: true, sd: null };
};
componentDidMount() {
this.unsubscribe = RQ.store.listen(function() {
this.state.sd.setState({ open: true });
});
};
componentWillUnmount() {
this.unsubscribe();
};
render() {
let menuItems = [
{ route: 'get-started', text: 'Get Started' },
{ route: 'customization', text: 'Customization' },
{ route: 'components', text: 'Components' }
];
return (
<LeftNav ref={(c) => this.state.sd = c} docked={false} openRight={true} menuItems={menuItems} />
);
};
}
侧边栏组件在另一个组件中呈现:
<ComSidebar ref={(c) => sdref = c} />
如果我手动调用sdref.state.sd.open = true,它工作得很好。
this.state.sd.setState({ open: true });应该是 this.setState({open: true}).
export class Sidebar extends React.Component<ISidebarProps, ISidebarState> {
unsubscribe: any;
constructor(props: ISidebarProps) {
super(props);
this.state = { shown: true, sd: null };
this.storeDidChange = this.storeDidChange.bind(this);
};
componentDidMount() {
this.unsubscribe = RQ.store.listen(this.storeDidChange);
};
componentWillUnmount() {
this.unsubscribe();
};
storeDidChange() {
this.refs.leftnav.open = true;
}
render() {
let menuItems = [
{ route: 'get-started', text: 'Get Started' },
{ route: 'customization', text: 'Customization' },
{ route: 'components', text: 'Components' }
];
return (
<LeftNav ref={leftnav} docked={false} openRight={true} menuItems={menuItems} />
);
};
}
JavaScript 中的 this
关键字经常以令人惊讶的方式运行。你找到了主要的。
当您使用 function
关键字创建内部函数时,它不会获得与封闭函数相同的 this
变量。这意味着,在您的代码中:
componentDidMount() {
// "this" out here is your component instance
this.unsubscribe = RQ.store.listen(function() {
// "this" in here is NOT the same - undefined, as you're seeing
this.setState({ open: true });
});
};
有几种方法可以解决这个问题。由于您使用的是 ES6,因此最简单的方法可能是使用箭头函数 - 箭头函数明确保留其封闭函数的 this
引用。它看起来像这样:
componentDidMount() {
this.unsubscribe = RQ.store.listen(() => {
// now it's the same "this"
this.setState({ open: true });
});
};
如果你没有使用 ES6,你可以通过在该函数上调用 bind
来获得相同的行为(它允许你指定 this
变量,以及它的任何参数):
componentDidMount() {
this.unsubscribe = RQ.store.listen(function() {
this.setState({ open: true });
}.bind(this));
// by calling bind, we are explicitly setting the "this" variable here
// passing it from outer scope to inner scope
};
我正在尝试在我的 ReactJs 应用程序中使用 Reflux。
我遇到一个问题,侦听数据存储的组件正在空组件实例而不是实例化的实际组件上执行回调。
调用操作 toggleUserBar 后,将调用数据存储并执行触发器。在组件Sidebar中调用了回调但是组件状态为空:
Uncaught TypeError: Cannot read property 'sd' of undefined
知道我做错了什么吗?
actions.tsx
var Reflux = require('reflux');
var RQ = {};
RQ.actions = Reflux.createActions([
"toggleUserBar"
]);
window.RQ = RQ;
store.tsx
RQ.store = Reflux.createStore({
listenables: [RQ.actions],
init: function() {},
onToggleUserBar: function() {
this.trigger();
}
});
sidebar.tsx
import * as React from "react";
import * as ReactDOM from "react-dom";
const LeftNav = require('material-ui/lib/left-nav');
const Menu = require('material-ui/lib/menu/menu')
interface ISidebarProps extends React.Props<any> {
}
interface ISidebarState extends React.Props<any> {
shown: Boolean;
sd: any;
}
export class Sidebar extends React.Component<ISidebarProps, ISidebarState> {
unsubscribe: any;
constructor(props: ISidebarProps) {
super(props);
this.state = { shown: true, sd: null };
};
componentDidMount() {
this.unsubscribe = RQ.store.listen(function() {
this.state.sd.setState({ open: true });
});
};
componentWillUnmount() {
this.unsubscribe();
};
render() {
let menuItems = [
{ route: 'get-started', text: 'Get Started' },
{ route: 'customization', text: 'Customization' },
{ route: 'components', text: 'Components' }
];
return (
<LeftNav ref={(c) => this.state.sd = c} docked={false} openRight={true} menuItems={menuItems} />
);
};
}
侧边栏组件在另一个组件中呈现:
<ComSidebar ref={(c) => sdref = c} />
如果我手动调用sdref.state.sd.open = true,它工作得很好。
this.state.sd.setState({ open: true });应该是 this.setState({open: true}).
export class Sidebar extends React.Component<ISidebarProps, ISidebarState> {
unsubscribe: any;
constructor(props: ISidebarProps) {
super(props);
this.state = { shown: true, sd: null };
this.storeDidChange = this.storeDidChange.bind(this);
};
componentDidMount() {
this.unsubscribe = RQ.store.listen(this.storeDidChange);
};
componentWillUnmount() {
this.unsubscribe();
};
storeDidChange() {
this.refs.leftnav.open = true;
}
render() {
let menuItems = [
{ route: 'get-started', text: 'Get Started' },
{ route: 'customization', text: 'Customization' },
{ route: 'components', text: 'Components' }
];
return (
<LeftNav ref={leftnav} docked={false} openRight={true} menuItems={menuItems} />
);
};
}
JavaScript 中的 this
关键字经常以令人惊讶的方式运行。你找到了主要的。
当您使用 function
关键字创建内部函数时,它不会获得与封闭函数相同的 this
变量。这意味着,在您的代码中:
componentDidMount() {
// "this" out here is your component instance
this.unsubscribe = RQ.store.listen(function() {
// "this" in here is NOT the same - undefined, as you're seeing
this.setState({ open: true });
});
};
有几种方法可以解决这个问题。由于您使用的是 ES6,因此最简单的方法可能是使用箭头函数 - 箭头函数明确保留其封闭函数的 this
引用。它看起来像这样:
componentDidMount() {
this.unsubscribe = RQ.store.listen(() => {
// now it's the same "this"
this.setState({ open: true });
});
};
如果你没有使用 ES6,你可以通过在该函数上调用 bind
来获得相同的行为(它允许你指定 this
变量,以及它的任何参数):
componentDidMount() {
this.unsubscribe = RQ.store.listen(function() {
this.setState({ open: true });
}.bind(this));
// by calling bind, we are explicitly setting the "this" variable here
// passing it from outer scope to inner scope
};