Динамическая загрузка из API SVG через хуки ReactJS

#javascript #reactjs #svg #frontend

#javascript #reactjs #svg #интерфейс

Вопрос:

У меня есть модуль, который отображает svg. Перед этим модуль должен проверить авторизацию и, если все в порядке, извлечь файл из api через вызов с помощью токена.

У меня есть следующий код

   function App() {
  const [tableColors, setTableColors] = useState(["gray"]);
  const [svg, setSvg] = useState(false);
  const [isLoaded, setIsLoaded] = useState(false);
  const [isErrored, setIsErrored] = useState(false);
  
  
  new AuthService().getUser().then(user =>{ if(!user) {
    Login()
  }
    else{
      useEffect( async () => {
        LoadSvg()
        .then(res => res.text())
        .then(setSvg)
        .catch(setIsErrored)
        .then(() => setIsLoaded(true))
      }, [])
    }})

  return ( 
    <div className="App">
      <header className="App-header">
       <SvgLoader svgXML={svg}>
       
      </SvgLoader> 
      
      </header>
    </div>
  );
  
  function Login(){
   var a = new AuthService();
   a.login();
  }

  async function LoadSvg(){
    return await new ApiService().callApi("https://localhost:44338/api/v1/desk-booking/Plan/getroomplanbyid?roomId=1")
  }
}
 

И проблема, с которой я сталкиваюсь здесь, заключается в том, что «useEffect»useEffect» не может быть вызван внутри обратного вызова», но без использования «useEffect» он бесконечно извлекает svg.

Как я могу решить проблему?

Комментарии:

1. useEffect не следует использовать условно. Глядя на код, я бы сказал, что вам также нужно поместить свою аутентификацию в useEffect.

2. Это первое правило хуков: вызывать хуки только на верхнем уровне. reactjs.org/docs/hooks-rules.html

Ответ №1:

Вы делаете это неправильно, если вы делаете это «реагирующим» способом, тогда решение будет выглядеть так

 ....
function App() {
  const [tableColors, setTableColors] = useState(['gray']);
  const [svg, setSvg] = useState(false);
  const [isLoaded, setIsLoaded] = useState(false);
  const [isErrored, setIsErrored] = useState(false);
  // state to check if user is loaded, used for svg call
  const [userLoaded, setUserLoaded] = useState(false);

  // useEffect does not prefer async function 
  useEffect(() => {
    if (!userLoaded) {
      new AuthService().getUser().then(user => {
        if (!user) {
          Login();
          // indicate user was loaded
          // I would move the login function body here instead since, login is async, so this might not work as intended but you get the idea
          setUserLoaded(true);
        }
      });
    }
  }, [])

  useEffect(() => {
    // if userLoaded is true then go ahead with svg loading
    if (userLoaded) {
      LoadSvg()
        .then(res => res.text())
        .then(setSvg)
        .catch(setIsErrored)
        .then(() => setIsLoaded(true));

    }
    // Add svg useEffect dependency on userLoaded
  }, [userLoaded]);
......
 

Обратите внимание, это решение предназначено для того, чтобы дать вам представление о том, как это сделать, оно может не сработать, если вы скопируете и вставите код.