Soweit ich verstanden habe, kann ich refs für ein einzelnes Element wie dieses verwenden:
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")
);
<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>
Wie kann ich dies für ein Array von Elementen implementieren? Offensichtlich nicht so: (Ich wusste es, obwohl ich es nicht ausprobiert habe :)
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")
);
<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>
Ich habe das und damit das gesehen . Aber ich bin immer noch verwirrt darüber, wie ich diesen Vorschlag für diesen einfachen Fall umsetzen soll.
javascript
reactjs
react-hooks
Devserkan
quelle
quelle
useRef()
einmal anrufen , warum erwarten Sie dann, dass die Elemente unterschiedliche Refs haben? AFAIK, React verwendet die Referenz als Kennung für iterierte Elemente, sodass der Unterschied zwischen ihnen nicht bekannt ist, wenn Sie dieselbeAntworten:
Ein Ref ist zunächst nur ein
{ current: null }
Objekt.useRef
behält den Verweis auf dieses Objekt zwischen Komponentenrenderen bei.current
value ist hauptsächlich für Komponentenreferenzen gedacht, kann aber alles enthalten.Irgendwann sollte es eine Reihe von Refs geben. Falls die Länge des Arrays zwischen den Renderings variieren kann, sollte ein Array entsprechend skaliert werden:
const arrLength = arr.length; const [elRefs, setElRefs] = React.useState([]); React.useEffect(() => { // add or remove refs setElRefs(elRefs => ( Array(arrLength).fill().map((_, i) => elRefs[i] || createRef()) )); }, [arrLength]); return ( <div> {arr.map((el, i) => ( <div ref={elRefs[i]} style={...}>...</div> ))} </div> );
Dieses Stück Code kann durch Abwickeln optimiert werden
useEffect
und ersetztuseState
mit ,useRef
aber es sollte diese Funktion in machen dabei Nebenwirkungen beobachtet wird , wird in der Regel eine schlechte Praxis in Betracht gezogen:const arrLength = arr.length; const elRefs = React.useRef([]); if (elRefs.current.length !== arrLength) { // add or remove refs elRefs.current = Array(arrLength).fill().map((_, i) => elRefs.current[i] || createRef()) )); } return ( <div> {arr.map((el, i) => ( <div ref={elRefs.current[i]} style={...}>...</div> ))} </div> );
quelle
useEffect
und angeben, denke ich. Angenommen, ich möchte die Breite dieser Elemente mithilfe von Refs ermitteln, wie ich es in meinem ersten Beispiel getan habe.setElWidth(elRef.current.map(innerElRef => innerElRef.current.offsetWidth)]
.map((el, i) => ...
.Da Sie keine Hooks in Schleifen verwenden können , finden Sie hier eine Lösung, damit sie funktioniert, wenn sich das Array im Laufe der Zeit ändert.
Ich nehme an, das Array stammt von den Requisiten:
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> )); }
quelle
itemsRef
scheint die Signatur zu sein:const itemsRef = useRef<Array<HTMLDivElement | null>>([])
this.itemsRef = []
. Anschließend müssen Sie den useEffect-Code innerhalb der componentDidUpdate-Lebenszyklusmethode verschieben. Schließlich sollten Sie in derrender
Methode<div key={i} ref={el =>
this.itemsRef.current [i] = el} `verwenden, um die Refs zu speichernEs gibt zwei Möglichkeiten
const inputRef = useRef([]); inputRef.current[idx].focus(); <input ref={el => inputRef.current[idx] = el} />
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"));
<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>
Verwenden Sie ein Array von ref
Wie im obigen Beitrag erwähnt, wird es nicht empfohlen, da die offizielle Richtlinie (und die Prüfung der inneren Flusen) nicht zulassen, dass es bestanden wird.
Da dies jedoch nicht unser aktueller Fall ist, funktioniert die folgende Demo weiterhin, wird jedoch nicht empfohlen.
const inputRef = list.map(x => useRef(null)); inputRef[idx].current.focus(); <input ref={inputRef[idx]} />
Code-Snippet anzeigen
const {useRef} = React; const App = () => { const list = [...Array(8).keys()]; const inputRef = list.map(x => useRef(null)); const handler = idx => () => { const next = inputRef[idx + 1]; if (next) { next.current.focus(); } }; return ( <div className="App"> <div className="input_boxes"> {list.map(x => ( <div> <input key={x} ref={inputRef[x]} onChange={handler(x)} type="number" className="otp_box" /> </div> ))} </div> </div> ); } ReactDOM.render(<App />, document.getElementById("root"));
<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>
quelle
showCallout()
auf reagieren-native-KartenMarker
sBeachten Sie, dass Sie useRef aus einem einfachen Grund nicht in einer Schleife verwenden sollten: Die Reihenfolge der verwendeten Hooks spielt eine Rolle!
Die Dokumentation sagt
Bedenken Sie jedoch, dass dies offensichtlich für dynamische Arrays gilt. Wenn Sie jedoch statische Arrays verwenden (Sie rendern IMMER die gleiche Anzahl von Komponenten), machen Sie sich darüber keine allzu großen Sorgen. Achten Sie darauf, was Sie tun, und nutzen Sie diese 😉
quelle
Sie können ein Array (oder ein Objekt) verwenden, um alle Refs zu verfolgen, und eine Methode verwenden, um dem Array Refs hinzuzufügen.
HINWEIS: Wenn Sie Refs hinzufügen und entfernen, müssen Sie das Array bei jedem Renderzyklus leeren.
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> ); }
Arbeitsbeispiel https://codesandbox.io/s/serene-hermann-kqpsu
quelle
!refs.current.includes(el)
?Angenommen, Ihr Array enthält keine Grundelemente, können Sie a
WeakMap
als Wert für verwendenRef
.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> ) }
quelle
Wir können state nicht verwenden, da der ref verfügbar sein muss, bevor die Rendermethode aufgerufen wird. Wir können useRef nicht beliebig oft aufrufen, aber wir können es einmal aufrufen:
Angenommen, es
arr
ist eine Requisite mit einer Reihe von Dingen:const refs = useRef([]); // free any refs that we're not using anymore refs.current = refs.current.slice(0, arr.length); // initialize any new refs for (let step = refs.current.length; step < arr.length; step++) { refs.current[step] = createRef(); }
quelle
useEffect()
....avoid setting refs during rendering — this can lead to surprising behavior. Instead, typically you want to modify refs in event handlers and effects.
reactjs.org/docs/…Wenn ich das richtig verstehe,
useEffect
sollte es nur für Nebenwirkungen verwendet werden, aus diesem Grund habe ich mich stattdessen für die Verwendung entschiedenuseMemo
.const App = props => { const itemsRef = useMemo(() => Array(props.items.length).fill().map(() => createRef()), [props.items]); return props.items.map((item, i) => ( <div key={i} ref={itemsRef[i]} style={{ width: `${(i + 1) * 100}px` }}> ... </div> )); };
Wenn Sie dann die Elemente manipulieren / Nebenwirkungen verwenden möchten, können Sie Folgendes tun:
useEffect(() => { itemsRef.map(e => e.current).forEach((e, i) => { ... }); }, [itemsRef.length])
quelle