[英]Why is my React component rendering twice?
我正在使用React-hooks
和Context API
进行 state 管理。 当consumer
组件呈现时,我已经控制台注销了context
state。 在console
中,我注意到context
中的 state 被注销了两次。 这是为什么?
我正在使用fetch API
从我的本地node
服务器中提取数据。 因此,在console
的前几行中,我得到了context
的初始 state,例如undefined
、 null
- 然后就在它下面,我得到了从服务器中提取的更新后的 state。
我创建了一个“主” context
来共享我将在整个应用程序中使用的functions
。 fetch
function 正在使用async/await
:
import React, { Component, createContext } from 'react';
export const MasterContext = createContext();
export class MasterProvider extends Component {
state = {
fetchData: async (url) => {
let res = await fetch(url);
let data = await res.json();
return data;
}
}
render() {
return (
<MasterContext.Provider value={{...this.state}}>
{this.props.children}
</MasterContext.Provider>
);
}
}
我有两个组件,使用两个不同的contexts
- 一个context
非常简单
state = {
title: '',
body: '',
cta: {
text: ''
},
img: '',
setHeaderPromo: (res) => {
this.setState({
title: res[0].title,
body: res[0].body,
cta: {...this.state.cta, ...res[0].cta},
img: res[0].img
});
}
}
为这个组件拉入的数据只是一个带有单个object
的简单array
。
这是consumer
组件:
const HeaderPromo = () => {
const {title, body, cta, img, setHeaderPromo} = useContext(HeaderContext);
const {fetchData} = useContext(MasterContext);
useEffect(() => {
fetchData(`http://localhost:5000/api/header`)
.then((res) => {
setHeaderPromo(res);
});
}, [fetchData, setHeaderPromo]);
console.log(title);
return (
<article className="cp-header__promo">
<div className="cp-header__promo__image">
<img src={img} alt="promo"/>
</div>
<div className="cp-header__promo__copy">
<h3>{title}</h3>
<p>{body}</p>
<button>{cta.text}</button>
</div>
</article>
);
}
所以,这在技术上是可行的。 但是,我注意到当我注销title
变量时,它会得到 output 两次。 第一次是context
的初始 state ,第二次是输出数据的内容。 为什么这样做?
我的问题在于我的第二个组件 - context
state 只是一个空array
,在fetch
请求后被填充。
第二种context
:
state = {
albums: null,
setNewReleases: (res) => {
this.setState({
albums: res
});
}
}
这是两个consumer
组件:
const NewReleases = () => {
const {albums, setNewReleases} = useContext(NewReleaseContext);
const {fetchData} = useContext(MasterContext);
useEffect(() => {
fetchData(`http://localhost:5000/api/new-releases`)
.then((res) => {
setNewReleases(res);
});
}, [fetchData, setNewReleases]);
console.log('from newRelease component', albums);
return (
<section className="cp-new-releases">
<Row sectionHeading={`New Releases`} albums={albums}/>
</section>
);
}
export default NewReleases;
因此, albums
变量再次被注销两次。 首先,最初的 state,然后数据被拉入,并再次记录。
现在,我将这个albums
变量作为prop
传递给<Row/>
组件。
行组件:
const Row = ({sectionHeading, albums}) => {
console.log('from row component', albums);
return (
<Fragment>
<div className="cp-new-releases__row">
{(sectionHeading) && (<h3 className="row-title">{sectionHeading}</h3>)}
<div className="cp-new-releases__row__album-container">
{albums.map((item, index) => (
<Album img={item.img} title={item.title} key={index}/>
))}
</div>
</div>
</Fragment>
);
}
export default Row;
现在albums
变量是一个包含两个objects
的array
。 如果我尝试遍历array
,它会抛出错误Uncaught TypeError: Cannot read property 'map' of null
。
我可以解决这个问题的唯一方法是进行if
检查以查看albums
是否具有价值。
const Row = ({sectionHeading, albums}) => {
console.log('from row component', albums);
return (
<Fragment>
<div className="cp-new-releases__row">
{(sectionHeading) && (<h3 className="row-title">{sectionHeading}</h3>)}
<div className="cp-new-releases__row__album-container">
{(albums) ? (
albums.map((item, index) => (
<Album img={item.img} title={item.title} key={index}/>
))
) : (<p style={{color: 'red'}}>no album</p>)}
</div>
</div>
</Fragment>
);
}
export default Row;
它试图遍历context
的初始 state 。 有人可以解释发生了什么,以及如何改进我的代码吗?
我知道这是冗长的。 所以,如果你坚持到最后,你就是冠军。
谢谢
FetchData 是一个异步操作 - 所以你的问题是你在从服务器获取数据之前添加了 Row 组件。 暂缓渲染<Row>
直到您收集了您的相册。
return (
<section className="cp-new-releases">
{ albums && // you might also want to test length here
// - unless you want to show a message in your
// Row component, indicating that non were found.
<Row sectionHeading={`New Releases`} albums={albums}/>
}
</section>
);
现在你的 Row 元素不是在初始加载时创建的,而是等到你得到数据,然后添加它。 想像一下,调用 function,您不会不必要地调用它,并且只能使用有效数据。 最终,这就是您将组件添加到渲染 function 时所做的事情。 所以你必须添加条件逻辑,因为组件是有效的函数,应该根据你的特定用例的逻辑来调用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.