1

Hi I am quite new to react and this is for a learning project. In react under next.js want to check for the existence of a certain folder on the server. To achieve that I implemented an api twigExists.js in pages/api and a custom hook twigExistsRequest.js in the library folder:

import {useEffect, useRef} from "react";
import {webApiUrl} from "@/library/webHelpers";

export function useTwigExistsRequest({
    parentDirSegment,
    name,
    action,
    treeStateDispatch
}) {
    const nameExists = useRef('not');
    useEffect(() => {
        if ('' !== name) {
            async function fetchNameValidation() {
                try {
                    const response = await fetch(
                        webApiUrl() + '/branchName',
                        {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: JSON.stringify({parentDirSegment, name})
                        }
                    );
                    const answer = await response.json();
                    if (undefined !== answer['exists']) {
                        nameExists.current = answer['exists'];
                    }
                    else if (undefined !== answer['err']) {
                        console.log(answer['err']);
                    }
                } catch (err) {
                    console.log(err);
                }
            }
            fetchNameValidation().then(() => {
                nameExists.current === 'exists'
                && treeStateDispatch({
                    action,
                    name,
                    dirSegment: parentDirSegment
                });
            })
        }
    });
}

The following error is thrown at the useRef line, line 10:

Error: Invalid hook call. Hooks can only be called inside of the body of a function component.

I am using an almost identical approach to get the structure of a special folder with its subfolders and it is working fine. Working example:

import {useEffect, useRef} from "react";
import {webApiUrl} from "@/library/webHelpers";

export default function useChangeBranchRequest({
   data,
   setData
}) {
    let postData;
    const storeEffect = useRef(0);
    if ('skip' !== data) {
        storeEffect.current += 1;
        postData = JSON.stringify(data);
    }
    useEffect(() => {
        if (0 !== storeEffect.current) {
            async function fetchData() {
                try {
                    const response = await fetch(
                  webApiUrl() + '/changeBranch',
                    {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json'
                            },
                            body: postData
                        });
                    const json = await response.json();
                    setData(JSON.parse(json['tree']));
                } catch (error) {
                    console.log(error);
                }
            }
            fetchData()
                .then(() => {
                return (<></>);
            });
        }
    }, [storeEffect.current]);
}

I can't see: What is wrong in the first example??

Edit due to question: useTwigExistsRequest is called from this file:

import {useTwigExistsRequest} from "@/library/twigExistsRequest";
    
    export default function twigExistsHandler({
        parentDirSegment,
        name,
        action,
        treeStateDispatch
    }) {
    
        useTwigExistsRequest({
            parentDirSegment,
            action,
            name,
            treeStateDispatch
        });
    
    }

trying to avoid a direct call from:

import {ACTIONS} from "@/library/common";
import {useState} from "react";
import twigExistsHandler from "@/library/twigExistsHandler";

export default function PlgButton({dirSegment, action, text, treeStateDispatch}) {

    const [info, SetInfo] = useState('');
    const [parentDirSegment, SetParentDirSegment] = useState('');

    // name validation, triggered by SetInfo. Returns strings 'false' or 'true':


    // reset Button after execution
    if (info) SetInfo('');

    return (
      <button
          className="btn btn-secondary btn-sm new-plg-btn"
          onClick={() => {
              clickHandler(action);
          }}
      >
          {text}
      </button>
    );

    function clickHandler(action) {
        let name;
        switch (action) {
            case ACTIONS.add:
                name = window.prompt('New name:');
                twigExistsHandler({
                    parentDirSegment: dirSegment,
                    name,
                    action,
                    treeStateDispatch
                });
                break;

            case ACTIONS.dup:
                name = window.prompt('Dup name:');
                twigExistsHandler({
                    parentDirSegment: dirSegment.slice(0,dirSegment.lastIndexOf('/')),
                    name,
                    action,
                    treeStateDispatch
                });
                break;

            case ACTIONS.del:
                window.confirm('Irrevocably delete the whole playground?')
                && treeStateDispatch({
                    info: '',
                    dirSegment,
                    action
                });
                break;
        }
    }
}
ejoo
  • 51
  • 1
  • 7
  • How did you use `useTwigExistsRequest`? Do you use it in functional component? – Lin Du Jun 20 '22 at 09:45
  • @slideshowp2 I have added the calling code. – ejoo Jun 20 '22 at 13:25
  • 1
    Please read [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html) – Lin Du Jun 21 '22 at 01:32
  • @slideshowp2 I solved the problem by moving the check for the existence of that directories into the serverside code. I am not sure, why the second example worked, with a very similar approach. Was the mistake here, that I call my custom hook NOT from another custom hook/react component? – ejoo Jun 29 '22 at 08:04

0 Answers0