我试图解决此问题,但是我没有运气...
我正在使用React和'react-bootstrap'。如下面的代码所示,使用useState
从firebase获取数据。但我也将模态称为组件,该模态使用useState
来显示和隐藏模态。
export const Models = () => {
const [models, setModels] = useState(null);
useEffect(() => {
firebase.database().ref('Models').on('value', (snapshot) => {
setModels(snapshot.val())
});
}, []);
return models;
}
当我单击URL来访问模态时出现问题,结果显示出来,主要组件转到firebase并尝试再次获取数据。因此,如果在模式上单击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;
感谢您的时间!
答案 0 :(得分:0)
模型是常规的javascript函数,而不是功能组件。因此,这不是对钩子的有效使用,并且无法按预期工作。请参阅rules of hooks上的文档。
一个功能组件接收道具并返回JSX或另一个React元素。
由于没有启用,因此基本上是重新启动并在每次由父级调用效果时调用效果。
查看所做的编辑,您可能应该只删除Models
函数并将逻辑放在Gallery
组件中。
答案 1 :(得分:0)
我阅读上述组件的方式使您似乎已经定义了一个自定义钩子,用于从Firebase获取数据。
因此,首先,我将其重命名为useFbData并将其视为自定义钩子,以便您可以使用ESLint Plugin for Hooks并确保遵循rules of hooks。
上面的方法,如果它是组件中的一个函数,则该函数将在每个渲染器上触发,因此您所描述的行为是我所期望的。
取决于您的请求的成本/该组件呈现的频率,这可能就是您想要的,因为您可能不想将过时的数据返回到您的组件。但是,如果您认为应该缓存来自数据库的响应,并且有一些使数据无效的逻辑,则可以尝试如下操作:
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的原因是,效果钩子不会获取依赖项数组中的数据(如果使用state,它将无限期循环)。
这将在每个调用之间保留数据库响应的结果,并防止多次调用,直到您使之无效为止。不过请记住,这将意味着您使用的数据在保存无效之前都是过时的。