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.