我正在使用React-hooks
和Context API
进行状态管理。当context
组件呈现时,我已控制台退出consumer
状态。在console
中,我注意到context
的状态被注销两次。这是为什么?
我正在使用fetch API
从本地node
服务器提取数据。因此,在console
的前几行中,我得到了context
的初始状态,例如undefined
,null
-然后,在此之下,我得到了更新状态从服务器提取的数据。
我创建了一个“母版” context
,以共享我将在整个应用程序中使用的functions
。 fetch
函数正在使用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
});
}
}
为此组件提取的数据只是一个简单的array
和一个object
。
这是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
变量时,它得到两次输出。第一次是context
的初始状态,第二次它输出数据的内容。为什么这样做?
我的问题出在我的第二个组件上-context
状态只是一个空的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
变量再次注销两次。首先是初始状态,然后是数据,然后再次记录。
现在,我将这个albums
变量作为<Row/>
传递给prop
组件。
行组件:
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
变量是一个包含两个array
的{{1}}。如果我尝试遍历objects
,则会抛出错误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;
的初始状态。有人可以解释发生了什么事,以及如何改善我的代码吗?
我知道这很困难。因此,如果您最终做到这一点,那您将是一个冠军。
谢谢
答案 0 :(得分:2)
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元素不是在初始加载时创建的,而是要等到获得数据后再添加它。可以将其想像成是调用一个函数,而不必仅使用有效数据调用它。最终,这就是将组件添加到渲染函数时要执行的操作。因此,您必须添加条件逻辑,因为组件是有效的功能,应根据您特定用例的逻辑进行调用。