为什么 useRef 从不从 null 更新 current?
Why does useRef never update current from null?
问题: 无法将 ref 从 {current: null} 更新为组件上的实际 ref。
我想要发生的事情: {current: null},据我所知,应该更新以包含 ref 开启的 div,以便成为能够点击它的外部(最终关闭它)。 9 了解它不会在第一次渲染时更新,但它永远不会更新。它在页面加载时执行 运行 两次,均返回 current: null.
我尝试了什么: 我已经遵循了所有 SO 建议来使用 useEffect,然后最终将它分离到这个函数中,这似乎是最合适和最新的方法做这个。它只是从不更新当前。
function useOutsideAlerter(ref) {
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
console.log(ref);
} else {
console.log("else", ref);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
}
export const Modal = (props) => {
const [showModal, setShowModal] = useState(props.showModal);
const wrapperRef = useRef(null);
useOutsideAlerter(wrapperRef);
return (
<Layout>
<ModalOuter
showModal={showModal || props.showModal}
id={styles["modalOuter"]}
handleClose={props.handleClose}
>
<ModalInner
ref={wrapperRef}
handleClose={props.handleClose}
>
<Layout display="flex" flexDirection="column">
<Layout display="flex" flexDirection="column">
<ModalTitle title={props.title} />
</Layout>
<HR />
<Layout display="flex" flexDirection="column">
<ModalBody body={props.body} />
</Layout>
</Layout>
</ModalInner>
</ModalOuter>
</Layout>
);
};
ModalInner
export const ModalInner = (props) => {
return (
<Layout
id={props.id}
ref={props.ref}
display="flex"
justifyContent="center"
alignItems="center"
padding="2rem"
margin="2rem"
backgroundColor="white"
>
{props.children}
</Layout>
);
};
布局组件
export const Layout = (props) => {
return (
<div
id={props.id}
ref={props.ref}
...
问题
在 React 中,有一些特殊的“道具”,ref
和 key
是其中的一对。我在 props
周围加上引号,因为当它们作为道具传递时,它们不会传递给子组件中的 props
对象或在其上可访问。
解决方案
使用 React.forwardRef
将任何传递的 React 引用转发给功能组件并将它们公开在子组件中。
export const ModalInner = React.forwardRef((props, ref) => { // <-- access ref
return (
<Layout
id={props.id}
ref={ref} // <-- pass ref *
display="flex"
justifyContent="center"
alignItems="center"
padding="2rem"
margin="2rem"
borderRadius="5px"
backgroundColor="white"
border={`1px solid ${Color.LightGray}`}
boxShadow={`0rem 0rem 1rem white`}
>
{props.children}
</Layout>
);
});
* 注意:Layout
和子组件同样需要转发 ref
直到到达它实际附加到 DOMNode 的位置。
另一种解决方案是将 ref 作为普通属性传递。
<ModalInner
wrapperRef={wrapperRef}
handleClose={props.handleClose}
>
...
export const ModalInner = (props) => {
return (
<Layout
id={props.id}
wrapperRef={props. wrapperRef} // <-- pass wrapperRef prop
display="flex"
justifyContent="center"
alignItems="center"
padding="2rem"
margin="2rem"
borderRadius="5px"
backgroundColor="white"
border={`1px solid ${Color.LightGray}`}
boxShadow={`0rem 0rem 1rem white`}
>
{props.children}
</Layout>
);
};
同样,您需要将 wrapperRef
道具钻到子级,直到您到达附加引用的实际 DOMNode。
例子
<div ref={props.wrapperRef> .... </div>
您可能还会发现 Refs and the DOM 文档对于使用 React 引用很有用。
问题: 无法将 ref 从 {current: null} 更新为组件上的实际 ref。
我想要发生的事情: {current: null},据我所知,应该更新以包含 ref 开启的 div,以便成为能够点击它的外部(最终关闭它)。 9 了解它不会在第一次渲染时更新,但它永远不会更新。它在页面加载时执行 运行 两次,均返回 current: null.
我尝试了什么: 我已经遵循了所有 SO 建议来使用 useEffect,然后最终将它分离到这个函数中,这似乎是最合适和最新的方法做这个。它只是从不更新当前。
function useOutsideAlerter(ref) {
useEffect(() => {
function handleClickOutside(event) {
if (ref.current && !ref.current.contains(event.target)) {
console.log(ref);
} else {
console.log("else", ref);
}
}
document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
}
export const Modal = (props) => {
const [showModal, setShowModal] = useState(props.showModal);
const wrapperRef = useRef(null);
useOutsideAlerter(wrapperRef);
return (
<Layout>
<ModalOuter
showModal={showModal || props.showModal}
id={styles["modalOuter"]}
handleClose={props.handleClose}
>
<ModalInner
ref={wrapperRef}
handleClose={props.handleClose}
>
<Layout display="flex" flexDirection="column">
<Layout display="flex" flexDirection="column">
<ModalTitle title={props.title} />
</Layout>
<HR />
<Layout display="flex" flexDirection="column">
<ModalBody body={props.body} />
</Layout>
</Layout>
</ModalInner>
</ModalOuter>
</Layout>
);
};
ModalInner
export const ModalInner = (props) => {
return (
<Layout
id={props.id}
ref={props.ref}
display="flex"
justifyContent="center"
alignItems="center"
padding="2rem"
margin="2rem"
backgroundColor="white"
>
{props.children}
</Layout>
);
};
布局组件
export const Layout = (props) => {
return (
<div
id={props.id}
ref={props.ref}
...
问题
在 React 中,有一些特殊的“道具”,ref
和 key
是其中的一对。我在 props
周围加上引号,因为当它们作为道具传递时,它们不会传递给子组件中的 props
对象或在其上可访问。
解决方案
使用 React.forwardRef
将任何传递的 React 引用转发给功能组件并将它们公开在子组件中。
export const ModalInner = React.forwardRef((props, ref) => { // <-- access ref
return (
<Layout
id={props.id}
ref={ref} // <-- pass ref *
display="flex"
justifyContent="center"
alignItems="center"
padding="2rem"
margin="2rem"
borderRadius="5px"
backgroundColor="white"
border={`1px solid ${Color.LightGray}`}
boxShadow={`0rem 0rem 1rem white`}
>
{props.children}
</Layout>
);
});
* 注意:Layout
和子组件同样需要转发 ref
直到到达它实际附加到 DOMNode 的位置。
另一种解决方案是将 ref 作为普通属性传递。
<ModalInner
wrapperRef={wrapperRef}
handleClose={props.handleClose}
>
...
export const ModalInner = (props) => {
return (
<Layout
id={props.id}
wrapperRef={props. wrapperRef} // <-- pass wrapperRef prop
display="flex"
justifyContent="center"
alignItems="center"
padding="2rem"
margin="2rem"
borderRadius="5px"
backgroundColor="white"
border={`1px solid ${Color.LightGray}`}
boxShadow={`0rem 0rem 1rem white`}
>
{props.children}
</Layout>
);
};
同样,您需要将 wrapperRef
道具钻到子级,直到您到达附加引用的实际 DOMNode。
例子
<div ref={props.wrapperRef> .... </div>
您可能还会发现 Refs and the DOM 文档对于使用 React 引用很有用。