Search code examples
javascriptreactjstypescriptreact-dom

How to use useParams hook and required type?


I have an example code:

function example() {
    const { id } = useParams();
    const [comments, setComments] = useState([]);

    useEffect(() => {
       customClass.getComments(id);
    })
}

customClass.getComments required id (number), so I have error:

Type 'undefined' is not assignable to type 'number'.

Ok, so I'm checking if id is not undefined:

function example() {
    const { id } = useParams();
    const [comments, setComments] = useState([]);

    if (!id) {
        return <Error />;
    }

    useEffect(() => {
       customClass.getComments(id);
    })
}

And now I have error:

React hook 'useEffect' is called conditionally. React Hooks must be called in the exact same order in every component render.

OK...

function example() {
    const { id } = useParams();
    const [comments, setComments] = useState([]);

    useEffect(() => {
       customClass.getComments(id);
    })

    if (!id) {
        return <Error />;
    }
}

And again:

Type 'undefined' is not assignable to type 'number'.

What is the best solution to make it work properly?

Maybe is possible to add "!" for useParam, but where?


Solution

  • I'm making an assumption that useParams doesn't load as soon as your page loads, and that's why you're getting undefined ids inside your useEffect.

    When useEffect is first called, id is still undefined. To fix that, you should call useEffect whenever id changes by adding it to the dependencies list.

    useEffect(() => {
     customClass.getComments(id);
    }, [id])
    

    But that still doesn't fix the following error

    Type 'undefined' is not assignable to type 'number'.

    To do so, you were on the right track, but added the if block on the wrong place. You should check inside the useEffect if your id is filled. Summing everything up, the following code should do the trick

    function example() {
        const { id } = useParams();
        const [comments, setComments] = useState([]);
    
        useEffect(() => {
           if (!id) return; // Guard clause to stop the error from happening
           customClass.getComments(id);
        }, [id])
    
        if (!id) {
            return <Error />;
        } else {
            return <></>
        }
    }