Реагируйте - проблемы с useState и Firebase - PullRequest
1 голос
/ 01 ноября 2019

Я пытался решить эту проблему, но мне не повезло ...

Я использую React и 'response-bootstrap'. Получение данных из firebase с помощью useState, как вы можете увидеть в следующем коде. Но также я вызываю модальное как компонент, и это модальное использование useState, чтобы показать и скрыть модальное.

export const Models = () => {

    const [models, setModels] = useState(null);

    useEffect(() => {
        firebase.database().ref('Models').on('value', (snapshot) => {
            setModels(snapshot.val())
        });

    }, []);
    return models;
}

проблема результата, когда я нажимаю на URL для доступа к модальному, этоодин из них показан, и главный компонент отправляется в базу данных и пытается снова получить данные. Итак, если я нажму 3 раза на модал, я получу свои данные из firebase 3 раза.

Как я могу это исправить? получить мои данные из firebase только один раз, независимо от того, когда вы открываете модальное окно?

Другая часть кода

const Gallery = () => {

    const [fireBaseDate, setFireBaseDate] = useState(null);
    axios.post('https://us-central1-models-gallery-puq.cloudfunctions.net/date',{format:'DD/MM/YYYY'})
    .then((response) => {
        setFireBaseDate(response.data)
    });

    let content = Models();
    let models = [];

    const [imageModalShow, setImageModalShow] = useState(false);
    const [selectedModel, setSelectedModel] = useState('');


    if(content){
        Object.keys(content).map((key, index) => 
        models[index] = content[key]
        );

        models = shuffleArray(models);
        console.log(models)

        return(
            <div className="appContentBody">
                <Jumbo />
                <Promotion models={models}/>
                <div className="Gallery">
                <h1>Galería - Under Patagonia</h1>

                <Filter />

                <div className="img-area">
                    {models.map((model, key) =>{
                        let myDate = new Date(model.creationDate);
                        let modelEndDate = new Date(myDate.setDate(myDate.getDate() + 30)).toLocaleDateString('en-GB')
                        if(fireBaseDate !== modelEndDate && model.active === true){
                            return (
                                <div className="img-card filterCard" key={key}>
                                    <div className="flip-img">
                                        <div className="flip-img-inner">
                                            <div className="flip-img-front">
                                                <img className="single-img card-img-top" src={model.thumbnail} alt="Model"/>
                                            </div>
                                            <div className="flip-img-back">
                                                <h2>{model.certified ? 'Verificada!' : 'No Verificada'}</h2>
                                                <p>Número: {model.contact_number}</p>
                                                <p>Ciudad: {model.city}</p>
                                                <p>Servicios: {model.services}</p>
                                            </div>
                                        </div>
                                    </div>
                                    <h5>{model.name}</h5>

                                    <Button variant="danger" onClick={() => {
                                                setImageModalShow(true)
                                                setSelectedModel(model)}
                                                }>
                                        Ver
                                    </Button>
                                </div>  
                            );
                        }
                    return 0})}                
                </div>
                    <Image
                        show={imageModalShow}
                        onHide={() => setImageModalShow(false)}
                        model={selectedModel}
                    />
                </div>
            <Footer />
            </div>
    )} else {
        return (
            <div className="loading">
                <h1>Loading...</h1>
            </div>
    )}
}


export default Gallery;

Спасибо за ваше время!

Ответы [ 2 ]

0 голосов
/ 01 ноября 2019

То, как я читаю ваш вышеупомянутый компонент, создает впечатление, что вы определили пользовательский хук для получения данных из firebase.

Итак, во-первых, я бы переименовал его в FbData и воспринимал его как пользовательский хук, чтобы вы могли использовать плагин ESLint для хуков и убедиться, что вы следуете правила хуков .

То, как вы это сделали выше, если это функция внутри компонента, ваша функция будет срабатывать при каждом рендеринге, поэтому описываемое вами поведение - то, что я ожидал,

В зависимости от того, насколько дорогим является ваш запрос / как часто этот компонент обрабатывается, это может быть тем, что вам нужно, поскольку вы, вероятно, не хотите возвращать устаревшие данные вашему компоненту. Однако, если вы чувствуете, что ответ из БД должен быть кэширован, и у вас есть логика для аннулирования этих данных, вы можете попробовать что-то вроде этого:

import { useEffect, useRef } from 'react';

const useFbData = invalidationFlag => {
  const data = useRef(null);
  useEffect(() => {
    if (!data.current || invalidationFlag) {
      firebase.database().ref('Data').on('value', (snapshot) => {
        data.current = snapshot.val();
      });
    }
  }, [invalidationFlag]);
  return data.current;
};

export default useFbData;

Таким образом, при первоначальном запуске и каждый раз, когда выизменил значение invalidationFlag, ваш эффект внутри хука useFbData запустится. При условии, что вы следите за invalidationFlag и устанавливаете его как требуется, это может сработать для вас.

Причина, по которой я использовал здесь ref вместо state, заключается в том, что ловушка эффекта не принимает данные вмассив зависимостей (который может привести к его бесконечному циклу, если мы используем состояние).

Это сохранит результат ответа db между каждым вызовом и предотвратит повторный вызов до тех пор, пока вы не сделаете недействительным. Помните, что это будет означать, что данные, которые вы используете, устарели, пока вы не сделаете их недействительными.

0 голосов
/ 01 ноября 2019

Модели - это обычная функция javascript, а не функциональный компонент. Так что это недопустимое использование хуков, и оно не будет работать так, как ожидалось. См. Документы по правилам хуков .

Функциональный компонент получает реквизиты и возвращает JSX или другой элемент React.

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

Глядя на ваше редактирование, вам, вероятно, следует просто удалить функцию Models и поместить логику в компонент Gallery.

...