我需要访问子组件的位置。据我了解,要访问子属性,我需要使用useImperativeHandle
将子API添加到其引用中。此外,我需要使用forwardRef
将引用从父级传输到子级。所以我这样做了:
const Text = React.forwardRef(({ onClick }, ref) => {
const componentAPI = {};
componentAPI.getLocation = () => {
return ref.current.getBoundingClientRect ? ref.current.getBoundingClientRect() : 'nope'
};
React.useImperativeHandle(ref, () => componentAPI);
return (<button onClick={onClick} ref={ref}>Press Me</button>);
});
Text.displayName = "Text";
const App = () => {
const ref = React.createRef();
const [value, setValue] = React.useState(null)
return (<div>
<Text onClick={() => setValue(ref.current.getLocation())} ref={ref} />
<div>Value: {JSON.stringify(value)}</div>
</div>);
};
ReactDOM.render(<App />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="app"></div>
如您所见,ref没有getBoundingClientRect
属性,但是如果我这样做,它将按预期工作:
const App = () => {
const ref = React.createRef();
const [value, setValue] = React.useState(null)
return (<div>
<button ref={ref} onClick={() => setValue(ref.current.getBoundingClientRect()) } ref={ref}>Press Me</button>
<div>Value: {JSON.stringify(value)}</div>
</div>);
};
ReactDOM.render(<App />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="app"></div>
那么我对useImperativeHanedle
和forwardRef
的理解又有什么问题呢?
答案 0 :(得分:1)
如docs所示(可能不够理解),子组件本身应具有不同的ref,并且通过useImperativeHandle可以定义一个将forwardedRef映射到子ref的函数:
import React from 'react'
import ReactDOM from 'react-dom'
const Text = React.forwardRef(({ onClick }, ref) => {
const buttonRef = React.useRef() // create a new ref for button
const componentAPI = {};
componentAPI.getLocation = () => {
return buttonRef.current.getBoundingClientRect ? buttonRef.current.getBoundingClientRect() : 'nope' // use buttonRef here
};
React.useImperativeHandle(ref, () => componentAPI); // this maps ref to buttonRef now
return (<button onClick={onClick} ref={buttonRef}>Press Me</button>); // set buttonRef
});
Text.displayName = "Text";
const App = () => {
const ref = React.useRef();
const [value, setValue] = React.useState(null)
return (<div>
<Text onClick={() => setValue(ref.current.getLocation())} ref={ref} />
<div>Value: {JSON.stringify(value)}</div>
</div>);
};
ReactDOM.render(<App />, document.querySelector("#app"))
答案 1 :(得分:1)
要使用func1() { echo $BASHPID; }
echo $BASHPID
28365
( func1 )
28627
,您需要使用另一个useImperativeHandle
实例,如下所示:
ref
如果您希望您的逻辑有效(使用转发的const Text = React.forwardRef(({ onClick }, ref) => {
const buttonRef = React.useRef();
React.useImperativeHandle(
ref,
() => ({
getLocation: () => buttonRef.current.getBoundingClientRect()
}),
[buttonRef]
);
return (
<button onClick={onClick} ref={buttonRef}>
Press Me
</button>
);
});
),这将起作用:
ref
为什么您的示例不起作用?
因为const Text = React.forwardRef(({ onClick }, ref) => {
React.useEffect(() => {
ref.current.getLocation = ref.current.getBoundingClientRect;
}, [ref]);
return (
<button onClick={onClick} ref={ref}>
Press Me
</button>
);
});
在ref.current.getBoundingClientRect
中分配(尝试记录它)时不可用,因为您实际上用useImperativeHandle
覆盖了按钮的ref
(请选中{{1 }},在挂载后为useImperativeHandle
分配了Text3
。
答案 2 :(得分:0)
我只是想添加此答案,以显示在删除无用的过度控制时事情如何变得更容易...
const Text = React.forwardRef(({ onClick }, ref) => {
ref.getLocation = () => ref.current && ref.current.getBoundingClientRect()
return (<button onClick={onClick} ref={ref}>Press Me</button>);
});
Text.displayName = "Text";
function App() {
const ref = { current: null };
const [value, setValue] = React.useState(null)
return (<div>
<Text onClick={() => setValue(ref.getLocation())} ref={ref} />
<div>Value: {JSON.stringify(value)}</div>
</div>);
}
ReactDOM.render(<App />, document.querySelector("#app"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="app"></div>
在上面的代码中,我们只使用forwardRef并将子API附加到它的ref上,这看起来很自然,而且非常人性化。
唯一会阻止您使用此方法的是React.createRef调用了Object.preventExtension()
(这使我的生活更加艰难...),因此,改用{ current: null }
的Object.preventExtension()
(基本相同)。