Skip to content

display value saved in useRef variable

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'

        });
    }

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.