我正在使用react-apollo开发一个react应用程序
当我检查浏览器网络选项卡响应时,通过graphql调用数据它显示数组的所有元素不同
但是我在我的应用程序中获得或console.log()
然后所有数组元素与第一个元素相同。
我不知道如何修复请帮助
答案 0 :(得分:5)
发生这种情况的原因是因为数组中的项目得到了标准化" Apollo缓存中的相同值。 AKA,他们看起来和阿波罗一样。这通常是因为它们共享相同的Symbol(id)
。
如果您打印出您的Apollo响应对象,您会注意到每个对象都有Symbol(id)
Apollo缓存使用的对象。您的数组项可能具有相同的Symbol(id)
,这会导致它们重复。为什么会这样?
默认情况下,Apollo缓存会运行此function进行规范化。
export function defaultDataIdFromObject(result: any): string | null {
if (result.__typename) {
if (result.id !== undefined) {
return `${result.__typename}:${result.id}`;
}
if (result._id !== undefined) {
return `${result.__typename}:${result._id}`;
}
}
return null;
}
您的数组项属性会导致多个项返回相同的数据ID。在我的情况下,多个项目_id = null
导致所有这些项目重复。当此函数返回null时,docs说
InMemoryCache将回退到查询中对象的路径, 例如ROOT_QUERY.allPeople.0为返回的第一条记录 allPeople根查询。
当我们的数组项与defaultDataIdFromObject
不兼容时,这就是我们实际想要的行为。
因此,解决方案是手动配置这些唯一标识符,并将dataIdFromObject
选项传递给InMemoryCache
中的ApolloClient
构造函数。以下内容适用于我,因为我的所有对象都使用_id并具有__typename。
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache({
dataIdFromObject: o => (o._id ? `${o.__typename}:${o._id}`: null),
})
});
答案 1 :(得分:4)
将此放入App.js
cache: new InMemoryCache({
dataIdFromObject: o => o.id ? `${o.__typename}-${o.id}` : `${o.__typename}-${o.cursor}`,
})
答案 2 :(得分:0)
我认为应避免使用其他两个答案中的方法,而应采用以下方法:
实际上,这很简单。要了解其工作原理,只需按如下所示记录obj:
const Section = ({ handleClick }) => {
return (
<div className="section">
Section
<Tile handleClick={handleClick} number="1" />
<Tile handleClick={handleClick} number="2" />
<Tile handleClick={handleClick} number="3" />
</div>
);
};
const Tile = ({ handleClick, number }) => {
return (
<div className="tile" onClick={() => handleClick(number)}>
tile {number}
</div>
);
};
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
modalOpen: false,
openedBy: ""
};
}
openModal = title => {
this.setState({
modalOpen: true,
openedBy: title
});
};
closeModal = () => {
this.setState({
modalOpen: false,
openedBy: ""
});
};
render() {
return (
<div className="App">
<div>ModalOpen = {this.state.modalOpen.toString()}</div>
<div>Opened by = {this.state.openedBy}</div>
<Section handleClick={this.openModal} />
<a href="#" onClick={this.closeModal}>
Close modal
</a>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
如果遇到此问题,您将在日志中看到id为空。
请注意已记录的“ obj”。它将为返回的每个对象打印。
这些对象是Apollo试图从中获取唯一ID的对象(您必须告诉Apollo,该对象中的哪个字段对于从GraphQL返回的“项目”数组中的每个对象都是唯一的-与传递唯一方法相同呈现DOM元素时使用“地图”或其他迭代时,React中“键”的值)。
默认情况下,InMemoryCache将尝试使用常见的 id和_id的唯一标识符的唯一标识符(如果存在) 以及对象上的__typename。
因此,请查看'defaultDataIdFromObject'使用的记录的'obj'-如果看不到'id'或'_id',则应在对象中提供每个对象唯一的字段。
我将示例从Apollo dox更改为涉及三种情况,当您可能提供了不正确的标识符时-这是针对您具有多个GraphQL类型的情况:
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
我希望您现在看到其他两个答案中的方法都是有风险的。
您始终具有唯一的标识符。只需让对象知道该字段即可轻松帮助阿波罗。如果未通过添加查询定义来获取,则将其添加。