在 React 中将数据从一个函数传递到另一个函数
Passing data from one function to another in React
所以我正在使用 P5 和 ML5,并且我在 React 中与它们一起工作,所以这让我跳过了一些障碍来让事情正常进行。
我正在尝试获取标签名称,以便在网络摄像头上绘制。
我可以获得 console.log 以在 gotResults 函数中记录标签名称,但我不确定我将如何使用它来让它在 gotResults 之外工作。
还是编码新手所以请原谅我:)
import React, { useRef, useEffect, useState } from 'react';
import p5, { VIDEO } from 'p5'
import ml5 from 'ml5'
const Webcam = props => {
const myRef = useRef();
const [label, setLabel] = useState([
{ label: 'Starting Label', confidence: 0 },
]);
useEffect(() => {
let myp5 = new p5(sketch, myRef.current)
});
const sketch = (p) => {
let mobilenet;
let cam;
let classifier;
let thumbUpRight;
let thumbDownRight;
let thumbUpLeft;
let thumbDownLeft;
let trainButton;
// let label = '';
const modelReady = () => {
console.log('Model is ready!');
}
const videoReady = () => {
console.log('Video is ready!');
}
const whileTraining = (loss) => {
if (loss == null) {
console.log('Training Complete')
classifier.classify(gotResults)
} else {
console.log(loss)
}
}
const gotResults = (error, result) => {
if (error) {
console.error(error);
} else {
// console.log(result)
setLabel(result);
classifier.classify(gotResults);
}
}
p.setup = () => {
p.createCanvas(640, 550);
cam = p.createCapture(VIDEO);
cam.hide();
p.background(0)
mobilenet = ml5.featureExtractor('MobileNet', modelReady)
classifier = mobilenet.classification(cam, videoReady)
thumbUpRight = p.createButton('Up Right');
thumbUpRight.mousePressed(function () {
classifier.addImage('thumbUpRight');
})
thumbDownRight = p.createButton('Down Right');
thumbDownRight.mousePressed(function () {
classifier.addImage('thumbDownRight');
})
thumbUpLeft = p.createButton('Up Left');
thumbUpLeft.mousePressed(function () {
classifier.addImage('thumbUpLeft');
})
thumbDownLeft = p.createButton('Down Left');
thumbDownLeft.mousePressed(function () {
classifier.addImage('thumbDownLeft');
})
trainButton = p.createButton('Train');
trainButton.mousePressed(function () {
classifier.train(whileTraining);
})
};
p.draw = () => {
p.background(0);
p.image(cam, 0, 0)
p.fill(255);
p.textSize(32);
p.text(label[0].label, 10, 530);
}
};
return (
<div ref={myRef}>
</div>
)
}
export default Webcam;
编辑:所以错误与状态重置、重新渲染网络摄像头以及每次调用 ML5 时的所有内容有关?我猜,这就像每次击中 ML5 时都重新绘制 api.. ?
你能label
状态吗?
const [label, setLabel] = useState('')
和
const gotResults = (error, results) => {
if (error) {
console.error(error);
} else {
// console.log(results)
setLabel(results[0].label)
mobilenet.predict(gotResults)
}
}
然后,您可以在 Webcam
函数的任何地方使用 label
。
似乎这些重新渲染正在发生,因为 classifier.classify(gotResults)
函数将执行多次,并且您正在使用 setLabel(result)
更新状态,这将导致重新渲染 evetime 它正在叫。您可以对此发表评论并检查它是否是罪魁祸首。如果是,那么您应该将 results
与 label
进行浅比较,并且仅在这些对象不同时才更新状态 setLabel(result)
:
在更新状态之前浅比较 result
与 label
:
const gotResults = (error, result) => {
if (error) {
console.error(error);
} else {
if (!areEqualShallow(label, result) {
setLabel(result);
}
classifier.classify(gotResults);
}
}
function areEqualShallow(a, b) {
for (var key in a) {
if (a[key] !== b[key]) {
return false;
}
}
return true;
}
如果这不是这些重新渲染的罪魁祸首,那么您应该检查 useEffect
钩子。我不知道你是否有意这样做,但是如果有一个 useEffect
钩子而不带任何参数,它将在每个渲染器上执行该钩子。
Does useEffect run after every render? Yes! By default, it runs both after the first render and after every update. (We will later talk about how to customize this.) Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.
此挂钩将 运行 用于每个渲染:
useEffect(() => {
let myp5 = new p5(sketch, myRef.current)
});
在 useEffect
挂钩的末尾添加一个空数组到 运行 它仅一次:
useEffect(() => {
let myp5 = new p5(sketch, myRef.current)
}, []);
更新
要更新现有 P5 对象上的标签,您必须使用 redraw
。您必须在 label
状态变量上创建一个效果挂钩,当 label
更改时将调用它:
// Set a P5 ref so you can use it again
const p5Ref = useRef();
// Change the initial hook to set the p5Ref
useEffect(() => {
p5Ref.current = new p5(sketch, myRef.current);
}, []);
// This effect will run only when the whole label object is updated,
// not just when a label.<prop> is updated
useEffect(() => {
// I'm not sure if that's going to work,
// you'll have to test and see how to force redraw using the P5 returned object properly
if (p5Ref && p5Ref.current) {
p5Ref.current.redraw();
}
}, [label]);
当然,如果您只是由于对象引用而更改 label
值,则此挂钩不会触发,因此您必须在使用 label
更新时创建一个新对象=30=] 像这样:
const gotResults = (error, result) => {
if (error) {
console.error(error);
} else {
// Create a new object so we'll get the update effect hook to trigger on label change
setLabel({ ...result });
classifier.classify(gotResults);
}
}
所以我正在使用 P5 和 ML5,并且我在 React 中与它们一起工作,所以这让我跳过了一些障碍来让事情正常进行。
我正在尝试获取标签名称,以便在网络摄像头上绘制。 我可以获得 console.log 以在 gotResults 函数中记录标签名称,但我不确定我将如何使用它来让它在 gotResults 之外工作。
还是编码新手所以请原谅我:)
import React, { useRef, useEffect, useState } from 'react';
import p5, { VIDEO } from 'p5'
import ml5 from 'ml5'
const Webcam = props => {
const myRef = useRef();
const [label, setLabel] = useState([
{ label: 'Starting Label', confidence: 0 },
]);
useEffect(() => {
let myp5 = new p5(sketch, myRef.current)
});
const sketch = (p) => {
let mobilenet;
let cam;
let classifier;
let thumbUpRight;
let thumbDownRight;
let thumbUpLeft;
let thumbDownLeft;
let trainButton;
// let label = '';
const modelReady = () => {
console.log('Model is ready!');
}
const videoReady = () => {
console.log('Video is ready!');
}
const whileTraining = (loss) => {
if (loss == null) {
console.log('Training Complete')
classifier.classify(gotResults)
} else {
console.log(loss)
}
}
const gotResults = (error, result) => {
if (error) {
console.error(error);
} else {
// console.log(result)
setLabel(result);
classifier.classify(gotResults);
}
}
p.setup = () => {
p.createCanvas(640, 550);
cam = p.createCapture(VIDEO);
cam.hide();
p.background(0)
mobilenet = ml5.featureExtractor('MobileNet', modelReady)
classifier = mobilenet.classification(cam, videoReady)
thumbUpRight = p.createButton('Up Right');
thumbUpRight.mousePressed(function () {
classifier.addImage('thumbUpRight');
})
thumbDownRight = p.createButton('Down Right');
thumbDownRight.mousePressed(function () {
classifier.addImage('thumbDownRight');
})
thumbUpLeft = p.createButton('Up Left');
thumbUpLeft.mousePressed(function () {
classifier.addImage('thumbUpLeft');
})
thumbDownLeft = p.createButton('Down Left');
thumbDownLeft.mousePressed(function () {
classifier.addImage('thumbDownLeft');
})
trainButton = p.createButton('Train');
trainButton.mousePressed(function () {
classifier.train(whileTraining);
})
};
p.draw = () => {
p.background(0);
p.image(cam, 0, 0)
p.fill(255);
p.textSize(32);
p.text(label[0].label, 10, 530);
}
};
return (
<div ref={myRef}>
</div>
)
}
export default Webcam;
编辑:所以错误与状态重置、重新渲染网络摄像头以及每次调用 ML5 时的所有内容有关?我猜,这就像每次击中 ML5 时都重新绘制 api.. ?
你能label
状态吗?
const [label, setLabel] = useState('')
和
const gotResults = (error, results) => {
if (error) {
console.error(error);
} else {
// console.log(results)
setLabel(results[0].label)
mobilenet.predict(gotResults)
}
}
然后,您可以在 Webcam
函数的任何地方使用 label
。
似乎这些重新渲染正在发生,因为 classifier.classify(gotResults)
函数将执行多次,并且您正在使用 setLabel(result)
更新状态,这将导致重新渲染 evetime 它正在叫。您可以对此发表评论并检查它是否是罪魁祸首。如果是,那么您应该将 results
与 label
进行浅比较,并且仅在这些对象不同时才更新状态 setLabel(result)
:
在更新状态之前浅比较 result
与 label
:
const gotResults = (error, result) => {
if (error) {
console.error(error);
} else {
if (!areEqualShallow(label, result) {
setLabel(result);
}
classifier.classify(gotResults);
}
}
function areEqualShallow(a, b) {
for (var key in a) {
if (a[key] !== b[key]) {
return false;
}
}
return true;
}
如果这不是这些重新渲染的罪魁祸首,那么您应该检查 useEffect
钩子。我不知道你是否有意这样做,但是如果有一个 useEffect
钩子而不带任何参数,它将在每个渲染器上执行该钩子。
Does useEffect run after every render? Yes! By default, it runs both after the first render and after every update. (We will later talk about how to customize this.) Instead of thinking in terms of “mounting” and “updating”, you might find it easier to think that effects happen “after render”. React guarantees the DOM has been updated by the time it runs the effects.
此挂钩将 运行 用于每个渲染:
useEffect(() => {
let myp5 = new p5(sketch, myRef.current)
});
在 useEffect
挂钩的末尾添加一个空数组到 运行 它仅一次:
useEffect(() => {
let myp5 = new p5(sketch, myRef.current)
}, []);
更新
要更新现有 P5 对象上的标签,您必须使用 redraw
。您必须在 label
状态变量上创建一个效果挂钩,当 label
更改时将调用它:
// Set a P5 ref so you can use it again
const p5Ref = useRef();
// Change the initial hook to set the p5Ref
useEffect(() => {
p5Ref.current = new p5(sketch, myRef.current);
}, []);
// This effect will run only when the whole label object is updated,
// not just when a label.<prop> is updated
useEffect(() => {
// I'm not sure if that's going to work,
// you'll have to test and see how to force redraw using the P5 returned object properly
if (p5Ref && p5Ref.current) {
p5Ref.current.redraw();
}
}, [label]);
当然,如果您只是由于对象引用而更改 label
值,则此挂钩不会触发,因此您必须在使用 label
更新时创建一个新对象=30=] 像这样:
const gotResults = (error, result) => {
if (error) {
console.error(error);
} else {
// Create a new object so we'll get the update effect hook to trigger on label change
setLabel({ ...result });
classifier.classify(gotResults);
}
}