Ich versuche, diese coole <canvas>
Animation, die ich hier gefunden habe, in eine wiederverwendbare React-Komponente umzuwandeln . Es sieht so aus, als würde diese Komponente eine übergeordnete Komponente für die Zeichenfläche und viele untergeordnete Komponenten für die Zeichenfläche erfordern function Ball()
.
Aus Leistungsgründen wäre es wahrscheinlich besser, die Balls
zu zustandslosen Komponenten zu machen, da es viele davon geben wird. Ich bin nicht so vertraut mit der Herstellung zustandsloser Komponenten und habe mich gefragt, wo ich die this.update()
und this.draw
Funktionen definieren soll, die in definiert sind function Ball()
.
Gehen Funktionen für zustandslose Komponenten innerhalb oder außerhalb der Komponente? Mit anderen Worten, welche der folgenden Möglichkeiten ist besser?
1:
const Ball = (props) => {
const update = () => {
...
}
const draw = () => {
...
}
return (
...
);
}
2:
function update() {
...
}
function draw() {
...
}
const Ball = (props) => {
return (
...
);
}
Was sind die Vor- und Nachteile von jedem und ist einer von ihnen besser für bestimmte Anwendungsfälle wie meinen?
Antworten:
Als erstes ist zu beachten, dass zustandslose Funktionskomponenten keine Methoden haben können. Sie sollten nicht mit einem Aufruf
update
oderdraw
einem gerendertenBall
Gerät rechnen, wenn es sich um eine zustandslose Funktionskomponente handelt.In den meisten Fällen sollten Sie die Funktionen außerhalb der Komponentenfunktion deklarieren, damit Sie sie nur einmal deklarieren und immer dieselbe Referenz wiederverwenden. Wenn Sie die Funktion im Inneren deklarieren, wird die Funktion jedes Mal neu definiert, wenn die Komponente gerendert wird.
Es gibt Fälle, in denen Sie eine Funktion innerhalb der Komponente definieren müssen, um sie beispielsweise als Ereignishandler zuzuweisen, der sich basierend auf den Eigenschaften der Komponente unterschiedlich verhält. Trotzdem können Sie die Funktion außerhalb definieren
Ball
und mit den Eigenschaften verknüpfen, wodurch der Code viel sauberer und die Funktionenupdate
oderdraw
wiederverwendbar werden.// You can use update somewhere else const update (propX, a, b) => { ... }; const Ball = props => ( <Something onClick={update.bind(null, props.x)} /> );
Wenn Sie Hooks verwenden , können Sie
useCallback
sicherstellen, dass die Funktion nur neu definiert wird, wenn sich eine ihrer Abhängigkeiten (props.x
in diesem Fall) ändert:const Ball = props => { const onClick = useCallback((a, b) => { // do something with a, b and props.x }, [props.x]); return ( <Something onClick={onClick} /> ); }
Das ist der falsche Weg :
const Ball = props => { function update(a, b) { // props.x is visible here } return ( <Something onClick={update} /> ); }
Wenn Sie
useCallback
dieupdate
Funktion imuseCallback
Hook selbst außerhalb der Komponente definieren, wird dies vor allem zu einer Entwurfsentscheidung. Sie sollten berücksichtigen, ob Sie sie wiederverwendenupdate
und / oder auf den Umfang des Verschlusses der Komponente zugreifen müssen. Lesen / Schreiben Sie beispielsweise in den Status. Persönlich definiere ich es standardmäßig innerhalb der Komponente und mache es nur dann wiederverwendbar, wenn dies erforderlich ist, um ein Über-Engineering von Anfang an zu verhindern. Darüber hinaus ist die Wiederverwendung von Anwendungslogik besser mit spezifischeren Hooks möglich, sodass Komponenten für Präsentationszwecke übrig bleiben. Das Definieren der Funktion außerhalb der Komponente während der Verwendung von Hooks hängt wirklich vom Grad der Entkopplung von React ab, den Sie für Ihre Anwendungslogik wünschen.quelle
this.draw
Funktion innerhalb der zusammenBall
. Es verwendet dasctx
von dem, was das übergeordnete Element wäre,<canvas>
und verwendet auch dasthis
Schlüsselwort für das, was die untergeordneteBall
Komponente wäre. Was wäre der beste Weg, um die zustandslose Komponente zu integrieren, damit auf beide Eigenschaften zugegriffen werden kann?this
Bei der Verwendung zustandsloser Funktionskomponenten gibt es keine , denken Sie daran. Für den Canvas-Kontext müsste man ihn an jeden einzelnen weitergebenBall
, was überhaupt nicht gut klingt.bind
speziell in Chrome vor 59 sogar langsamer als Pfeilfunktionen waren. Und in Firefox ist es auch eine ganze Weile her, da beide mit der gleichen Geschwindigkeit arbeiten. Also würde ich sagen, in solchen Fällen gibt es keinen Unterschied, was der bevorzugte Weg ist :)Something
Komponente zu wissen, dass sich in ihrer übergeordneten Komponente ein Prop X befindet, da sie auf ihren Kontext aufmerksam macht. Dasselbe gilt für die Frage, die Sie stellen, und für den Beispielcode, den ich geschrieben habe. Dies hängt vom Kontext ab, der der Einfachheit halber ignoriert wird.Wir können Funktionen in zustandslosen Funktionskomponenten haben. Das folgende Beispiel ist:
const Action = () => { function handlePick(){ alert("test"); } return ( <div> <input type="button" onClick={handlePick} value="What you want to do ?" /> </div> ); }
Dies ist jedoch keine gute Vorgehensweise, da die Funktion
handlePick()
jedes Mal definiert wird, wenn die Komponente aufgerufen wird.quelle
handlePick()
über / außerhalb der Komponente zu definierenfunction handlePick() { ... }; const Action = () => { ... }
, so dass das Ergebnis ist, dass handlePick nur einmal definiert wird. Wenn Sie Daten von derAction
Komponente benötigen , sollten Sie diese als Parameter an diehandlePick
Funktion übergeben.Wir können den React-Hook
useCallback
wie folgt in einer Funktionskomponente verwenden:const home = (props) => { const { small, img } = props const [currentInd, setCurrentInd] = useState(0); const imgArrayLength = img.length - 1; useEffect(() => { let id = setInterval(() => { if (currentInd < imgArrayLength) { setCurrentInd(currentInd => currentInd + 1) } else { setCurrentInd(0) } }, 5000); return () => clearInterval(id); }, [currentInd]); const onLeftClickHandler = useCallback( () => { if (currentInd === 0) { } else { setCurrentInd(currentInd => currentInd - 1) } }, [currentInd], ); const onRightClickHandler = useCallback( () => { if (currentInd < imgArrayLength) { setCurrentInd(currentInd => currentInd + 1) } else { } }, [currentInd], ); return ( <Wrapper img={img[currentInd]}> <LeftSliderArrow className={currentInd > 0 ? "red" : 'no-red'} onClick={onLeftClickHandler}> <img src={Icon_dir + "chevron_left_light.png"}></img> </LeftSliderArrow> <RightSliderArrow className={currentInd < imgArrayLength ? "red" : 'no-red'} onClick={onRightClickHandler}> <img src={Icon_dir + "chevron_right_light.png"}></img> </RightSliderArrow> </Wrapper>); } export default home;
Ich bekomme 'img' von seinem Elternteil und das ist ein Array.
quelle
Wenn Sie Requisiten oder den Status der Komponente in der Funktion verwenden möchten, sollte dies in der Komponente mit useCallback definiert werden.
function Component(props){ const onClick=useCallback(()=>{ // Do some things with props or state },[]) }
Wenn Sie dagegen keine Requisiten oder Statusfunktionen verwenden möchten, definieren Sie diese außerhalb der Komponente.
const computeSomethings=()=>{ // Do some things with params or side effects } function Component(props){ }
quelle