I have a variable
const prediction = useRef<any>(null);
I click on a button that runs a function which sets the value of my variable:
function showResult() {
classifier.current.classify(capture, (result) => {
prediction.current = result[0].label
console.log('prediction.current', prediction.current)
});
}
On the console log, I see the correct value for prediction.current. However, when I try to render it in JSX, I don’t get anything. What can I do to change this?
If I use setState inside the classifier.current.classifyfunction, it gives me different. It’s an ml5 function. Is there an alternate way? Could i somehow setState outside the function? useEffect maybe?
return (
<div>
<Button variant="contained" color="primary" onClick={() => gotResult()}>Test!</Button>
<br />
<span>Prediction: {prediction.current}</span><br />
</div>
</div>)
//const [prediction, setPrediction] = useState<string>();
//const [confidence, setConfidence] = useState<string>();
//const [imageClassifier, setClassifier] = useState<any>();
let capture: p5Types.Element;
const classifier = useRef<any>(null);
const prediction = useRef<any>(null);
const confidence = useRef<any>(null);
const setup = (p5: p5Types, canvasParentRef: Element) => {
capture = p5.createCapture(p5.VIDEO).parent(canvasParentRef);
const featureExtractor = ml5.featureExtractor('MobileNet', modelReady);
classifier.current = featureExtractor.classification(capture, videoReady);
console.log('start', classifier);
}
function showResult() {
console.log('classifier in results', classifier);
classifier.current.classify(capture, (result) => {
prediction.current = result[0].label;
console.log(result[0].confidence); // Should output 'dog'
});
}
Advertisement
Answer
A ref changing its current value does not trigger any re-renders in React components, but you should be able to replace the snippets above and trigger the re-render to see the latest value:
const prediction = useRef<any>(null);
Becomes:
const [prediction, setPrediction] = useState(null);
The getResult function would then look like:
function gotResult() {
classifier.current.classify(capture, (err: any, result: any) => {
setPrediction(result[0].label])
});
}
Finally the rendering:
return (
<div>
<Button variant="contained" color="primary" onClick={() => gotResult()}>Test!</Button>
<br />
<span>Prediction: {prediction}</span><br />
</div>
)
Your classifier is setting the current value on every render. You probably only want that whenever featureExtractor, capture or videoReady changes. You can do that with useMemo:
const classifier = useMemo(() => {
return featureExtractor.classification(capture, videoReady);
}, [featureExtractor, capture, videoReady]);
That dependency array in useMemo will make sure the classifier only gets defined if those variables change and not on every render.