在 React 中使用 document.querySelector?我应该使用 refs 吗?如何? [英] Using document.querySelector in React? Should I use refs instead? How?
问题描述
我现在正在用 React 构建一个旋转木马.要滚动到单个幻灯片,我使用 document.querySelector
像这样:
useEffect(() => {document.querySelector(`#slide-${activeSlide}`).scrollIntoView({行为:平稳",块:'最近的',内联:'最近的'});}, [activeSlide]);
这是不好的做法吗?毕竟,我在这里直接访问 DOM?这样做的 React 方式是什么?
完整的return
方法
返回 (<><button onClick={() =>setActiveSlide(moveLeft)}>PREV</button><包装器 id="测试">{children.map((child, i) => {返回 (<幻灯片id={`slide-${i}`} key={`slide-${i}`}>{孩子}</幻灯片>);})}</包装器><button onClick={() =>setActiveSlide(moveRight)}>NEXT</button></>);
我无法回答是否要为此使用 refs 的你应该"部分,除非你这样做,你不需要那些 id
值,除非您将它们用于其他用途.
但您可以这样做:
使用
useRef(null)
创建参考.const activeSlideRef = useRef(null);
把它放在当前处于活动状态的
Slide
在您的
useEffect
中,使用引用的current
属性useEffect(() => {如果(activeSlideRef.current){activeSlideRef.current.scrollIntoView({行为:平稳",块:'最近的',内联:'最近的'});}}, [activeSlide]);
(我认为
activeSlide
是该效果的合理依赖.您不能使用 ref,ref 本身不会变化......)
实时示例,为了方便起见,我已将您的一些组件转换为 div
:
const {useEffect, useRef, useState} = React;功能甲板({儿童}){const [activeSlide, setActiveSlide] = useState(0);const activeSlideRef = useRef(null);useEffect(() => {如果(activeSlideRef.current){activeSlideRef.current.scrollIntoView({行为:平稳",块:'最近的',内联:'最近的'});}}, [activeSlide]);const moveLeft = Math.max(0, activeSlide - 1);const moveRight = Math.min(children.length - 1, activeSlide + 1);返回 (<React.Fragment><button onClick={() =>setActiveSlide(moveLeft)}>PREV</button><div id="测试">{children.map((child, i) => {const active = i === activeSlide;返回 (<div className={`slide ${active ?活动":"}`} ref={active ?activeSlideRef : null} id={`slide-${i}`} key={`slide-${i}`}>{孩子}
);})}
<button onClick={() =>setActiveSlide(moveRight)}>NEXT</button></React.Fragment>);}ReactDOM.render(<甲板><div>幻灯片 0 </div><div>幻灯片 1 </div><div>幻灯片 2 </div><div>幻灯片 3 </div><div>幻灯片 4 </div><div>幻灯片 5 </div><div>幻灯片 6 </div><div>幻灯片 7 </div><div>幻灯片 8 </div><div>幻灯片 9 </div></甲板>,document.getElementById("root"));
.slide {高度:4em;垂直对齐:中间;文本对齐:居中;}#测试 {溢出:滚动;最大高度:20em;}.积极的 {字体粗细:粗体;颜色:蓝色;}
<div id="root"></div><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>
在您提出的评论中:
<块引用>你知道是否可以在第一次渲染时禁用 useEffect
吗?
为了保留每个组件的非状态信息,有趣的是您使用 useRef
.useRef
的文档指出,这不仅仅是对于 DOM 元素引用,它也适用于每个组件的非状态数据.所以你可以有
const firstRenderRef = useRef(true);
然后在您的 useEffect
回调中,检查 firstRenderRef.current
&mndash;如果它是 true
,设置它 false
,否则做滚动:
const {useEffect, useRef, useState} = React;功能甲板({儿童}){const [activeSlide, setActiveSlide] = useState(0);const activeSlideRef = useRef(null);//*** 使用初始值为 `true` 的 refconst firstRenderRef = useRef(true);console.log("渲染");useEffect(() => {//*** 渲染之后,什么都不做,记住我们已经看到了渲染如果(firstRenderRef.current){console.log("设置假");firstRenderRef.current = false;} else if (activeSlideRef.current) {console.log("滚动");activeSlideRef.current.scrollIntoView({行为:平稳",块:'最近的',内联:'最近的'});}}, [activeSlide]);const moveLeft = Math.max(0, activeSlide - 1);const moveRight = Math.min(children.length - 1, activeSlide + 1);返回 (<React.Fragment><button onClick={() =>setActiveSlide(moveLeft)}>PREV</button><div id="测试">{children.map((child, i) => {const active = i === activeSlide;返回 (<div className={`slide ${active ?活动":"}`} ref={active ?activeSlideRef : null} id={`slide-${i}`} key={`slide-${i}`}>{孩子}
);})}
<button onClick={() =>setActiveSlide(moveRight)}>NEXT</button></React.Fragment>);}ReactDOM.render(<甲板><div>幻灯片 0 </div><div>幻灯片 1 </div><div>幻灯片 2 </div><div>幻灯片 3 </div><div>幻灯片 4 </div><div>幻灯片 5 </div><div>幻灯片 6 </div><div>幻灯片 7 </div><div>幻灯片 8 </div><div>幻灯片 9 </div></甲板>,document.getElementById("root"));
.slide {高度:4em;垂直对齐:中间;文本对齐:居中;}#测试 {溢出:滚动;最大高度:10em;}.积极的 {字体粗细:粗体;颜色:蓝色;}
<div id="root"></div><script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.10.2/umd/react.production.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.10.2/umd/react-dom.production.min.js"></script>