Как исправить превышение максимального размера стека вызовов

# #node.js #reactjs #firebase #express

Вопрос:

У вас есть приложение MERN Firebase, и вы получаете эту ошибку и кучу других deepExtend (deepCopy.ts:71)

 RangeError: Maximum call stack size exceeded
getApps [as apps]
src/firebaseNamespaceCore.ts:172
  169 |  */
  170 | function getApps(): FirebaseApp[] {
  171 |   // Make a copy so caller cannot mutate the apps list.
> 172 |   return Object.keys(apps).map(name => apps[name]);
      | ^  173 | }
  174 | 
  175 | function registerComponent(
 

Это файл JS, вызывающий проблему. Я не могу этого понять.

 import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import { Row, Col, Image, ListGroup, Card, Button } from 'react-bootstrap';
import Rating from '../components/Rating';
import socketIOClient from 'socket.io-client';
import axios from 'axios';
// import Product from '../components/Product';
import dotenv from 'dotenv';
import { ReactMediaRecorder } from 'react-media-recorder';
import firebase from 'firebase';
import 'firebase/firestore';
import firebaseKeys from 'firebase';
const ENDPOINT = 'http://localhost:5000';

dotenv.config();
firebase.initializeApp(firebaseKeys);
firebase.analytics();
export const storage = firebase.storage();

const AudioPreview = ({ stream }) => {
  const audioRef = useRef(null);

  useEffect(() => {
    if (stream) audioRef.current.srcObject = stream;
  }, [stream]);

  if (!stream) return null;
  return <audio ref={audioRef} autoPlay controls />;
};

const VideoPreview = ({ stream }) => {
  const videoRef = useRef(null);

  useEffect(() => {
    if (stream) videoRef.current.srcObject = stream;
  }, [stream]);

  if (!stream) return null;
  return <video ref={videoRef} autoPlay controls />;
};

function Controls({ status, startRecording, stopRecording, mediaBlobUrl }) {
  const [url, setURL] = useState('');
  async function uploadFile() {
    const blob = await fetch(mediaBlobUrl).then((r) => r.blob());
    const path = '/recordings/one';
    firebase
      .storage()
      .ref(path)
      .put(blob)
      .then(function (snapshot) {
        console.log('Uploaded complete');
      });

    storage.ref(path).getDownloadURL().then(setURL);
  }
  return (
    <Row>
      <span className='uk-text-meta'>{status}</span>
      <button className='uk-margin-small-left' type='button' onClick={startRecording} disabled={status === 'recording'}>
        Start
      </button>
      <button className='uk-margin-small-left' type='button' onClick={stopRecording} disabled={status === 'stopped'}>
        Stop
      </button>
      <button className='uk-margin-small-left' type='button' onClick={uploadFile} disabled={status !== 'stopped'}>
        upload
      </button>
      {url amp;amp; (
        <a className='uk-margin-small-left' href={url} target='_blank' rel='noopener noreferrer'>
          open
        </a>
      )}
    </Row>
  );
}

function RecordAudio() {
  return (
    <ReactMediaRecorder
      audio
      render={({ status, startRecording, stopRecording, previewStream, mediaBlobUrl }) => (
        <div>
          {status === 'recording' ? (
            <AudioPreview stream={previewStream} />
          ) : (
            <audio src={mediaBlobUrl} controls autoPlay />
          )}
          <Controls
            status={status}
            startRecording={startRecording}
            stopRecording={stopRecording}
            mediaBlobUrl={mediaBlobUrl}
          />
        </div>
      )}
    />
  );
}

function RecordVideo() {
  return (
    <ReactMediaRecorder
      video
      render={({ status, startRecording, stopRecording, previewStream, mediaBlobUrl }) => (
        <div>
          {status === 'recording' ? (
            <VideoPreview stream={previewStream} />
          ) : (
            <video src={mediaBlobUrl} controls autoPlay />
          )}
          <Controls
            status={status}
            startRecording={startRecording}
            stopRecording={stopRecording}
            mediaBlobUrl={mediaBlobUrl}
          />
        </div>
      )}
    />
  );
}

// function RecordScreen() {
//   return (
//     <ReactMediaRecorder
//       screen
//       render={({ status, startRecording, stopRecording, mediaBlobUrl }) => (
//         <div>
//           <video src={mediaBlobUrl} controls autoPlay />
//           <Controls
//             status={status}
//             startRecording={startRecording}
//             stopRecording={stopRecording}
//             mediaBlobUrl={mediaBlobUrl}
//           />
//         </div>
//       )}
//     />
//   );
// }

function handleClick(num) {
  this.setState(num);
}

const ProductScreen = ({ match }) => {
  const [product, setProduct] = useState({});
  //const [state, setState] = useState(0);
  this.setState(0);

  useEffect(() => {
    console.log('about to fetch product');
    const fetchProduct = async () => {
      console.log('Below is the id param waht the fuck is it?');
      console.log(match.params.id);
      const { data } = await axios.get(`http://localhost:5000/api/products/${match.params.id}`);

      setProduct(data);
    };
    fetchProduct();
    const socket = socketIOClient(ENDPOINT);
    socket.on('status-update', function (call) {
      const stext = document.getElementById('statusText');
      stext.innerText = call;
    });
    // CLEAN UP THE EFFECT
    // return () => socket.disconnect();
  }, [match]);

  return (
    <>
      <Link className='btn btn-light my-3' to='/'>
        Go Back
      </Link>
      <Row>
        <Col md={6}>
          <Image src={product.image} alt={product.name} fluid />
        </Col>
        <Col md={3}>
          <ListGroup variant='flush'>
            <ListGroup.Item>
              <h3>{product.name}</h3>
            </ListGroup.Item>
            <ListGroup.Item>
              <Rating value={product.rating} text={`${product.numReviews} reviews`} />
            </ListGroup.Item>
            <ListGroup.Item>Price : {product.price}</ListGroup.Item>
            <ListGroup.Item>Description : {product.description}</ListGroup.Item>
          </ListGroup>
        </Col>
        <Col md={3}>
          <Card>
            <ListGroup variant='flush'>
              <ListGroup.Item>
                <Row>
                  <Col>Price: </Col>
                  <Col>
                    <strong>${product.price}</strong>
                  </Col>
                </Row>
              </ListGroup.Item>
            </ListGroup>
            <ListGroup variant='flush'>
              <ListGroup.Item>
                <Row>
                  <Col>Status: </Col>
                  <Col>{product.countInStock > 0 ? 'In Stock' : 'Out of Stock'}</Col>
                </Row>
              </ListGroup.Item>
              <ListGroup.Item>
                <Button
                  //   onClick={addToCartHandler}
                  className='btn-block w-100'
                  type='button'
                  disabled={product.countInStock === 0}
                >
                  Add To Cart
                </Button>
              </ListGroup.Item>
              <ListGroup.Item>
                <Row>
                  <Col>Copy Status: </Col>
                  <Col>
                    <h2 id='statusText'>Share</h2>
                    <button type='button' onClick={() => handleClick(1)}>
                      audio
                    </button>
                    <button type='button' onClick={() => handleClick(2)}>
                      video
                    </button>
                    {/* <button type="button" onClick={() => handleClick(3)}>
        screen
      </button> */}
                    {state === 1 amp;amp; <RecordAudio />}
                    {state === 2 amp;amp; <RecordVideo />}
                    {/* {state === 3 amp;amp; <RecordScreen />} */}
                  </Col>
                </Row>
              </ListGroup.Item>
            </ListGroup>
          </Card>
        </Col>
      </Row>
    </>
  );
};

export default ProductScreen;
 

Кроме того, получение основного пакета SDK Firebase JS всегда должно быть…. ОШИБКА?

У меня есть это в моем index.html

 <!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="theme-color" content="#000000" />
    <meta name="description" content="Web site created using create-react-app" />
    <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
    <link
      rel="stylesheet"
      href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css"
      referrerpolicy="no-referrer"
    />
    <title>Welcom To BShop</title>
  </head>
  <body>
    The core Firebase JS SDK is always required and must be listed first
    <script src="https://www.gstatic.com/firebasejs/8.7.1/firebase-app.js"></script>

    <!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->
    <script src="https://www.gstatic.com/firebasejs/8.7.1/firebase-analytics.js"></script>

    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>
 

ОБНОВЛЕНИЕ (проблема с firebase или перезагрузка firebase снова и снова?)

Если я закомментирую эти 3 строки и любую ссылку на хранилище

Затем ошибка исчезает.

 // firebase.initializeApp(firebaseKeys);
// firebase.analytics();
// export const storage = firebase.storage();
 

Это не аналитическая линия!

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

1. Это действительно поможет нам, если вы сведете свой код к минимуму, который вызывает проблему. Это избавляет нас от необходимости просматривать весь ваш код, чтобы понять, что происходит. Часто вы в конечном итоге сами находите проблему, просто пытаясь изолировать ее. Но, даже не читая ваш код, я держу пари, что вы запускаете setState рендеринг компонента изнутри.

2. Использование this.setState в функциональном компоненте, а также handleClick использование this.setState говорит мне, что здесь есть и другие проблемы, или вы делаете что-то очень сомнительное, чтобы заставить их работать..

3. Вы уверены match , что каждый рендеринг/запуск эффекта снова и снова не является новым объектом в сочетании с настройкой состояния продукта? Основываясь на ошибке, я бы сказал, что это довольно вероятно..

4. Обновлено, см. выше его огневую базу?

5. Вы нажимаете кнопку, чтобы запустить бесконечный цикл, или он делает это без какого-либо взаимодействия?

Ответ №1:

Хорошо, я оставил свой комментарий выше, а затем решил посмотреть, куда вы звоните setState — и вы делаете это непосредственно внутри рендеринга компонента. Вот оскорбительный код:

 const ProductScreen = ({ match }) => {
  const [product, setProduct] = useState({});
  const [state, setState] = useState(0);
  this.setState(0); // <- This is bad
  ...
}
 

Каждый раз, когда ваш ProductScreen просмотру, которому вы звоните setState , что приводит ProductScreen к визуализации, который затем вызывает setState снова, что приводит ProductScreen к визуализации, который затем вызывает setState снова, что приводит ProductScreen к визуализации, который затем вызывает setState снова, что приводит ProductScreen к визуализации, который затем вызывает setState снова, что приводит ProductScreen к визуализации, который затем вызывает setState снова, что приводит ProductScreen к визуализации, который затем вызывает setState снова, что приводит ProductScreen к визуализации снова, который затем вызывает setState снова.


Вы понимаете, в чем дело. Вы должны звонить только setState тогда, когда что — то происходит-например, в обработчике щелчка или useEffect крючке.

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

1. Как this.setState , в первую очередь, работать внутри функционального компонента?

2. Я удалил эту строку, и она все еще делает это.

3. @BrianThompson Я сразу же задался тем же вопросом. Кажется подозрительным, да, но поскольку this в компонентах функций не определено, я думаю, что там должна быть ошибка.

4. Снова. Эта строка была удалена. Проблема, по-видимому, связана с линиями огневой базы?

5. Я не прочитал весь ваш код, потому что там слишком много всего происходит. Если вы сократите свой код до минимально воспроизводимой версии, я посмотрю еще раз. Там есть что-то, что вызывает бесконечные рендеринги… но я не собираюсь просматривать весь этот код, чтобы найти его. Кроме того, this в вашем коде не должно быть ничего, так как вы используете функциональные компоненты.