无法通过 ref 访问子函数?
Unable to access child function via ref?
最初一切正常,我有一个类似的组件。
这个
class A extends React.Component {
constructor(props) {
super(props);
this.childRef = null
}
componentDidMount() {
this.childRef = this.refs.b
// now I can call child function like this
this.childRef.calledByParent()
}
render(){
<B ref = "b"/>
}
}
在其他文件中
class B extends React.Component {
calledByParent(){
console.log("i'm called")
}
render(){
<div> hello </div>
}
}
export default B
到这里它工作正常但是当我在 class B
export default connect(mapStateToProps, mapDispatchToProps)(B)
中做这样的事情时
它不起作用。我已经从 react-redux
导入了连接
connect()
接受 option
作为第四个参数。在此选项参数中,您可以将标志 withRef
设置为 true。在此之后,您可以使用 getWrappedInstance()
like
访问 refs 的函数
class A extends React.Component {
constructor(props) {
super(props);
this.childRef = null
}
componentDidMount() {
this.childRef.getWrappedInstance().calledByParent()
}
render(){
<B ref = {ref => this.childRef = ref}/>
}
}
class B extends React.Component {
calledByParent(){
console.log("i'm called")
}
render(){
<div> hello </div>
}
}
export default connect(mapStateToProps, mapDispatchToProps, null, {withRef: true})(B)
可能有点晚了,但比使用 refs 的另一个(更好的)解决方案是只控制组件的特定功能。
class A extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.ctrl_B.calledByParent()
}
render(){
<B provideCtrl={ctrl => this.ctrl_B = ctrl} />
}
}
class B extends React.Component {
componentDidMount() {
this.props.provideCtrl({
calledByParent: () => this.calledByParent()
});
}
componentWillUnmount() {
this.props.provideCtrl(null);
}
calledByParent(){
console.log("i'm called")
}
render(){
<div> hello </div>
}
}
export default connect(mapStateToProps, mapDispatchToProps)(B)
我遇到了类似的问题,但我不想让我的 API 依赖于 getWrappedInstance()
调用。事实上,您的 class 层次结构中的某些组件可能会使用 connect() 并访问商店,而其他一些组件只是无状态组件,不需要额外的 Redux 层。
我刚刚写了一个小方法(可能有点老套)。请注意,它尚未经过全面测试,因此您可能需要进行一些调整才能使其在您自己的场景中运行。
TypeScript(应该很容易转换为纯 JavaScript 语法):
function exposeWrappedMethods(comp: React.ComponentClass<any>, proto?: any): any {
if (!proto) {
if (comp.prototype.constructor.name === 'Connect') {
// Only Redux component created with connect() is supported
proto = comp.prototype.constructor.WrappedComponent.prototype;
} else {
console.warn('Trying to extend an invalid component.');
return comp;
}
}
let prototypeName: string = proto.constructor.name;
if (prototypeName.search(/^React.*Component.*/) < 0 && proto.__proto__) {
for (let propertyName of Object.getOwnPropertyNames(proto)) {
if (!comp.prototype[propertyName]) {
let type: string = typeof proto[propertyName];
if (type === 'function') {
// It's a regular function
comp.prototype[propertyName] = function (...args: any[]) {
return this.wrappedInstance[propertyName](args);
};
} else if (type === 'undefined') {
// It's a property
Object.defineProperty(comp.prototype, propertyName, {
get: function () {
return (this as any).wrappedInstance[propertyName];
},
set: function (value: any) {
(this as any).wrappedInstance[propertyName] = value;
}
});
}
}
}
return exposeWrappedMethods(comp, proto.__proto__);
}
return comp;
}
只需用 exposeWrappedMethods
包装您的 connect()
调用即可使用它。它将添加您自己的 class(和 subclasses)中的所有方法和属性,但不会覆盖已经存在的方法(即来自 React.Component base class 的方法)。
export default exposeWrappedMethods(
connect<any, any, Properties>(
(state: ApplicationState) => state.counter,
CounterState.actionCreators,
null,
{ pure: false, withRef: true } // It requires use of "withRef: true"
)(Counter)) as typeof Counter;
希望您(或其他人)觉得它有用。
/卢卡斯
最初一切正常,我有一个类似的组件。 这个
class A extends React.Component {
constructor(props) {
super(props);
this.childRef = null
}
componentDidMount() {
this.childRef = this.refs.b
// now I can call child function like this
this.childRef.calledByParent()
}
render(){
<B ref = "b"/>
}
}
在其他文件中
class B extends React.Component {
calledByParent(){
console.log("i'm called")
}
render(){
<div> hello </div>
}
}
export default B
到这里它工作正常但是当我在 class B
export default connect(mapStateToProps, mapDispatchToProps)(B)
它不起作用。我已经从 react-redux
导入了连接connect()
接受 option
作为第四个参数。在此选项参数中,您可以将标志 withRef
设置为 true。在此之后,您可以使用 getWrappedInstance()
like
class A extends React.Component {
constructor(props) {
super(props);
this.childRef = null
}
componentDidMount() {
this.childRef.getWrappedInstance().calledByParent()
}
render(){
<B ref = {ref => this.childRef = ref}/>
}
}
class B extends React.Component {
calledByParent(){
console.log("i'm called")
}
render(){
<div> hello </div>
}
}
export default connect(mapStateToProps, mapDispatchToProps, null, {withRef: true})(B)
可能有点晚了,但比使用 refs 的另一个(更好的)解决方案是只控制组件的特定功能。
class A extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.ctrl_B.calledByParent()
}
render(){
<B provideCtrl={ctrl => this.ctrl_B = ctrl} />
}
}
class B extends React.Component {
componentDidMount() {
this.props.provideCtrl({
calledByParent: () => this.calledByParent()
});
}
componentWillUnmount() {
this.props.provideCtrl(null);
}
calledByParent(){
console.log("i'm called")
}
render(){
<div> hello </div>
}
}
export default connect(mapStateToProps, mapDispatchToProps)(B)
我遇到了类似的问题,但我不想让我的 API 依赖于 getWrappedInstance()
调用。事实上,您的 class 层次结构中的某些组件可能会使用 connect() 并访问商店,而其他一些组件只是无状态组件,不需要额外的 Redux 层。
我刚刚写了一个小方法(可能有点老套)。请注意,它尚未经过全面测试,因此您可能需要进行一些调整才能使其在您自己的场景中运行。
TypeScript(应该很容易转换为纯 JavaScript 语法):
function exposeWrappedMethods(comp: React.ComponentClass<any>, proto?: any): any {
if (!proto) {
if (comp.prototype.constructor.name === 'Connect') {
// Only Redux component created with connect() is supported
proto = comp.prototype.constructor.WrappedComponent.prototype;
} else {
console.warn('Trying to extend an invalid component.');
return comp;
}
}
let prototypeName: string = proto.constructor.name;
if (prototypeName.search(/^React.*Component.*/) < 0 && proto.__proto__) {
for (let propertyName of Object.getOwnPropertyNames(proto)) {
if (!comp.prototype[propertyName]) {
let type: string = typeof proto[propertyName];
if (type === 'function') {
// It's a regular function
comp.prototype[propertyName] = function (...args: any[]) {
return this.wrappedInstance[propertyName](args);
};
} else if (type === 'undefined') {
// It's a property
Object.defineProperty(comp.prototype, propertyName, {
get: function () {
return (this as any).wrappedInstance[propertyName];
},
set: function (value: any) {
(this as any).wrappedInstance[propertyName] = value;
}
});
}
}
}
return exposeWrappedMethods(comp, proto.__proto__);
}
return comp;
}
只需用 exposeWrappedMethods
包装您的 connect()
调用即可使用它。它将添加您自己的 class(和 subclasses)中的所有方法和属性,但不会覆盖已经存在的方法(即来自 React.Component base class 的方法)。
export default exposeWrappedMethods(
connect<any, any, Properties>(
(state: ApplicationState) => state.counter,
CounterState.actionCreators,
null,
{ pure: false, withRef: true } // It requires use of "withRef: true"
)(Counter)) as typeof Counter;
希望您(或其他人)觉得它有用。
/卢卡斯