dev*_*kan 10 javascript reactjs react-hooks
据我了解,我可以将refs用于单个元素,如下所示:
const { useRef, useState, useEffect } = React;
const App = () => {
const elRef = useRef();
const [elWidth, setElWidth] = useState();
useEffect(() => {
setElWidth(elRef.current.offsetWidth);
}, []);
return (
<div>
<div ref={elRef} style={{ width: "100px" }}>
Width is: {elWidth}
</div>
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
如何为元素数组实现此功能?显然不是这样:(即使我没有尝试过,我也知道:)
const { useRef, useState, useEffect } = React;
const App = () => {
const elRef = useRef();
const [elWidth, setElWidth] = useState();
useEffect(() => {
setElWidth(elRef.current.offsetWidth);
}, []);
return (
<div>
{[1, 2, 3].map(el => (
<div ref={elRef} style={{ width: `${el * 100}px` }}>
Width is: {elWidth}
</div>
))}
</div>
);
};
ReactDOM.render(
<App />,
document.getElementById("root")
);Run Code Online (Sandbox Code Playgroud)
<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
<div id="root"></div>Run Code Online (Sandbox Code Playgroud)
kei*_*kai 26
有两种方式
const inputRef = useRef([]);
inputRef.current[idx].focus();
<input
ref={el => inputRef.current[idx] = el}
/>
Run Code Online (Sandbox Code Playgroud)
const inputRef = useRef([]);
inputRef.current[idx].focus();
<input
ref={el => inputRef.current[idx] = el}
/>
Run Code Online (Sandbox Code Playgroud)
const {useRef} = React;
const App = () => {
const list = [...Array(8).keys()];
const inputRef = useRef([]);
const handler = idx => e => {
const next = inputRef.current[idx + 1];
if (next) {
next.focus()
}
};
return (
<div className="App">
<div className="input_boxes">
{list.map(x => (
<div>
<input
key={x}
ref={el => inputRef.current[x] = el}
onChange={handler(x)}
type="number"
className="otp_box"
/>
</div>
))}
</div>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));Run Code Online (Sandbox Code Playgroud)
使用ref数组
正如上面的帖子所说,不推荐这样做,因为官方指南(和内部 lint 检查)不允许它通过。
不要在循环、条件或嵌套函数中调用 Hook。相反,始终在 React 函数的顶层使用 Hook。通过遵循此规则,您可以确保每次渲染组件时以相同的顺序调用 Hook。
但是,由于这不是我们当前的情况,因此下面的演示仍然有效,只是不推荐。
const inputRef = list.map(x => useRef(null));
inputRef[idx].current.focus();
<input
ref={inputRef[idx]}
/>
Run Code Online (Sandbox Code Playgroud)
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.12.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.12.0/umd/react-dom.production.min.js"></script>Run Code Online (Sandbox Code Playgroud)
const inputRef = list.map(x => useRef(null));
inputRef[idx].current.focus();
<input
ref={inputRef[idx]}
/>
Run Code Online (Sandbox Code Playgroud)
Emm*_*fon 18
上面的所有其他选项都依赖于数组,但它使事情变得极其脆弱,因为元素可能会被重新排序,然后我们不会跟踪哪个 ref 属于哪个元素。
React 使用keyprop 来跟踪项目。因此,如果您通过键存储引用,则不会有任何问题:
const useRefs = () => {
const refsByKey = useRef<Record<string,HTMLElement | null>>({})
const setRef = (element: HTMLElement | null, key: string) => {
refsByKey.current[key] = element;
}
return {refsByKey: refsByKey.current, setRef};
}
Run Code Online (Sandbox Code Playgroud)
const Comp = ({ items }) => {
const {refsByKey, setRef} = useRefs()
const refs = Object.values(refsByKey).filter(Boolean) // your array of refs here
return (
<div>
{items.map(item => (
<div key={item.id} ref={element => setRef(element, item.id)}/>
)}
</div>
)
}
Run Code Online (Sandbox Code Playgroud)
请注意,React 在卸载项目时,将调用提供的函数 with null,这会将对象中的匹配key条目设置为 null,因此所有内容都将是最新的。
Oli*_*ssé 15
由于您 不能在循环内使用钩子,因此有一种解决方案,可以使它在数组随时间变化时起作用。
我想数组来自props:
const App = props => {
const itemsRef = useRef([]);
// you can access the elements with itemsRef.current[n]
useEffect(() => {
itemsRef.current = itemsRef.current.slice(0, props.items.length);
}, [props.items]);
return props.items.map((item, i) => (
<div
key={i}
ref={el => itemsRef.current[i] = el}
style={{ width: `${(i + 1) * 100}px` }}>
...
</div>
));
}
Run Code Online (Sandbox Code Playgroud)
Moh*_*oly 12
useRef最简单、最有效的方法就是根本不使用。只需使用回调引用即可在每次渲染时创建新的引用数组。
function useArrayRef() {
const refs = []
return [refs, el => el && refs.push(el)]
}
Run Code Online (Sandbox Code Playgroud)
<div id="root"></div>
<script type="text/babel" defer>
const { useEffect, useState } = React
function useArrayRef() {
const refs = []
return [refs, el => el && refs.push(el)]
}
const App = () => {
const [elements, ref] = useArrayRef()
const [third, setThird] = useState(false)
useEffect(() => {
console.log(elements)
}, [third])
return (
<div>
<div ref={ref}>
<button ref={ref} onClick={() => setThird(!third)}>toggle third div</button>
</div>
<div ref={ref}>another div</div>
{ third && <div ref={ref}>third div</div>}
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
</script>
<script src="https://unpkg.com/@babel/standalone@7/babel.min.js"></script>
<script src="https://unpkg.com/react@17/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js"></script>Run Code Online (Sandbox Code Playgroud)
Est*_*ask 11
ref最初只是{ current: null }对象。useRef在组件渲染之间保留对此对象的引用。currentvalue主要用于组件引用,但可以容纳任何内容。
在某个时候应该有一组引用。如果数组长度是固定的,则可以是:
const elRef = useRef([...Array(3)].map(() => createRef()));
...
return (
<div>
{[1, 2, 3].map((el, i) => (
<div ref={elRef.current[i]} style={{ width: `${el * 100}px` }}>...</div>
))}
</div>
);
Run Code Online (Sandbox Code Playgroud)
您可以使用数组(或对象)来跟踪所有引用,并使用方法将引用添加到数组中。
注意:如果要添加和删除引用,则必须在每个渲染周期清空数组。
import React, { useRef } from "react";
const MyComponent = () => {
// intialize as en empty array
const refs = useRefs([]); // or an {}
// Make it empty at every render cycle as we will get the full list of it at the end of the render cycle
refs.current = []; // or an {}
// since it is an array we need to method to add the refs
const addToRefs = el => {
if (el && !refs.current.includes(el)) {
refs.current.push(el);
}
};
return (
<div className="App">
{[1,2,3,4].map(val => (
<div key={val} ref={addToRefs}>
{val}
</div>
))}
</div>
);
}
Run Code Online (Sandbox Code Playgroud)
工作示例 https://codesandbox.io/s/serene-hermann-kqpsu
我使用 useRef 挂钩来创建我想要独立控制的数据面板。首先,我初始化 useRef 来存储数组:
import React, { useRef } from "react";
const arr = [1, 2, 3];
const refs = useRef([])
Run Code Online (Sandbox Code Playgroud)
当初始化数组时,我们观察到它实际上是这样的:
//refs = {current: []}
Run Code Online (Sandbox Code Playgroud)
然后我们应用 map 函数来使用我们将引用的 div 标签创建面板,通过一键查看将当前元素添加到我们的 refs.current 数组中:
arr.map((item, index) => {
<div key={index} ref={(element) => {refs.current[index] = element}}>
{item}
<a
href="#"
onClick={(e) => {
e.preventDefault();
onClick(index)
}}
>
Review
</a>
})
Run Code Online (Sandbox Code Playgroud)
最后一个接收按下按钮索引的函数我们可以控制我们想要显示的面板
const onClick = (index) => {
console.log(index)
console.log(refs.current[index])
}
Run Code Online (Sandbox Code Playgroud)
最后完整的代码是这样的
import React, { useRef } from "react";
const arr = [1, 2, 3];
const refs = useRef([])
//refs = {current: []}
const onClick = (index) => {
console.log(index)
console.log(refs.current[index])
}
const MyPage = () => {
const content = arr.map((item, index) => {
<div key={index} ref={(element) => {refs.current[index] = element}}>
{item}
<a
href="#"
onClick={(e) => {
e.preventDefault();
onClick(index)
}}
>
Review
</a>
})
return content
}
export default MyPage
Run Code Online (Sandbox Code Playgroud)
这个对我有用!希望这些知识对您有用。
请注意,出于一个简单的原因,您不应该在循环中使用 useRef:使用的钩子的顺序很重要!
文档说
不要在循环、条件或嵌套函数中调用 Hook。相反,始终在 React 函数的顶层使用 Hook。通过遵循此规则,您可以确保每次渲染组件时以相同的顺序调用 Hook。这就是允许 React 在多个 useState 和 useEffect 调用之间正确保留 Hooks 状态的原因。(如果你很好奇,我们将在下面深入解释这一点。)
但是考虑到它显然适用于动态数组......但是如果你使用静态数组(你总是渲染相同数量的组件)不要太担心,注意你在做什么并利用它
假设您的数组包含非基元,您可以使用 aWeakMap作为 的值Ref。
function MyComp(props) {
const itemsRef = React.useRef(new WeakMap())
// access an item's ref using itemsRef.get(someItem)
render (
<ul>
{props.items.map(item => (
<li ref={el => itemsRef.current.set(item, el)}>
{item.label}
</li>
)}
</ul>
)
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7038 次 |
| 最近记录: |