如何使用 React apollo-client 缓存搜索数组?
How can I search an array with React apollo-client cache?
我有一个简单的搜索组件和 handleSearch 函数:
const { data, loading, error } = useQuery(QUERY_GET_ELEMENTS);
const client = useApolloClient();
<input
onChange={handleSearch}
placeholder="🔎 Search..."
/>
function handleSearch(e) {
const { value } = e.target;
const matchingElements = data.filter(({ name }) =>
name.toLowerCase().includes(value.toLowerCase())
);
client.writeData({
data: {
elements: matchingElements
}
});
}
// rendering the elements looks something like this:
data.elements.map(el => <div>{el.name}</div>
数据来自 useQuery 挂钩。
问题是搜索只能在一个方向上进行,因为一旦元素被过滤,我就会丢失原始列表。我需要存储所有我可以过滤的元素,并在保留原始列表的同时仅呈现过滤后的元素。
我正在使用 apollo 进行状态管理,但似乎无法正常工作。我的第一个想法是使用 client.writeData 复制元素并且永远不会修改,但是这没有按预期工作。
非常感谢任何帮助。
您应该可以使用 useState
挂钩来完成此操作。这个例子对我有用:
import React, { useState, useEffect } from 'react';
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks'
const QUERY_GET_ELEMENTS = gql`
{
elements {
id
name
}
}
`;
export default function Test() {
const [isDisplayDataSet, setIsDisplayDataSet] = useState(false);
const [displayData, setDisplayData] = useState([]);
const { data, loading, error } = useQuery(QUERY_GET_ELEMENTS);
useEffect(() => {
if (!loading && !isDisplayDataSet) {
setDisplayData(data.elements);
setIsDisplayDataSet(true);
}
}, [isDisplayDataSet, displayData, data, loading])
function handleSearch(e) {
const { value } = e.target;
const matchingElements = data.elements.filter(({ name }) =>
name.toLowerCase().includes(value.toLowerCase())
);
setDisplayData(matchingElements);
}
if (error) {
console.error(error);
return <h1>There was an error</h1>
}
if (isDisplayDataSet) {
return (
<>
<input
className="form-control mb-3"
onChange={handleSearch}
placeholder="🔎 Search..."
/>
<ul className="list-group">
{displayData.map(el => <li className="list-group-item" key={el.id}>{el.name}</li>)}
</ul>
</>
);
} else {
return '';
}
}
我添加了一些 bootstrap 类 用于造型 :)
这是我设置的用于加载一些数据的快速而简单的 apollo 服务器:
const { ApolloServer } = require('apollo-server');
const gql = require('graphql-tag');
const fetch = require('node-fetch');
const typeDefs = gql`
type Element {
id: ID!
name: String!
}
type Query {
elements: [Element]!
}
schema {
query: Query
}
`;
const resolvers = {
Query: {
async elements() {
const res = await fetch('https://reqres.in/api/users');
const { data } = await res.json();
const elements = data.map(({ id, first_name, last_name }) => ({ id, name: `${first_name} ${last_name}` }))
console.log('elements', elements);
return elements;
}
}
}
const server = new ApolloServer({
typeDefs,
resolvers
});
server.listen().then(({ url }) => {
console.log('server ready on ' + url);
});
我有一个简单的搜索组件和 handleSearch 函数:
const { data, loading, error } = useQuery(QUERY_GET_ELEMENTS);
const client = useApolloClient();
<input
onChange={handleSearch}
placeholder="🔎 Search..."
/>
function handleSearch(e) {
const { value } = e.target;
const matchingElements = data.filter(({ name }) =>
name.toLowerCase().includes(value.toLowerCase())
);
client.writeData({
data: {
elements: matchingElements
}
});
}
// rendering the elements looks something like this:
data.elements.map(el => <div>{el.name}</div>
数据来自 useQuery 挂钩。
问题是搜索只能在一个方向上进行,因为一旦元素被过滤,我就会丢失原始列表。我需要存储所有我可以过滤的元素,并在保留原始列表的同时仅呈现过滤后的元素。
我正在使用 apollo 进行状态管理,但似乎无法正常工作。我的第一个想法是使用 client.writeData 复制元素并且永远不会修改,但是这没有按预期工作。
非常感谢任何帮助。
您应该可以使用 useState
挂钩来完成此操作。这个例子对我有用:
import React, { useState, useEffect } from 'react';
import gql from 'graphql-tag';
import { useQuery } from '@apollo/react-hooks'
const QUERY_GET_ELEMENTS = gql`
{
elements {
id
name
}
}
`;
export default function Test() {
const [isDisplayDataSet, setIsDisplayDataSet] = useState(false);
const [displayData, setDisplayData] = useState([]);
const { data, loading, error } = useQuery(QUERY_GET_ELEMENTS);
useEffect(() => {
if (!loading && !isDisplayDataSet) {
setDisplayData(data.elements);
setIsDisplayDataSet(true);
}
}, [isDisplayDataSet, displayData, data, loading])
function handleSearch(e) {
const { value } = e.target;
const matchingElements = data.elements.filter(({ name }) =>
name.toLowerCase().includes(value.toLowerCase())
);
setDisplayData(matchingElements);
}
if (error) {
console.error(error);
return <h1>There was an error</h1>
}
if (isDisplayDataSet) {
return (
<>
<input
className="form-control mb-3"
onChange={handleSearch}
placeholder="🔎 Search..."
/>
<ul className="list-group">
{displayData.map(el => <li className="list-group-item" key={el.id}>{el.name}</li>)}
</ul>
</>
);
} else {
return '';
}
}
我添加了一些 bootstrap 类 用于造型 :)
这是我设置的用于加载一些数据的快速而简单的 apollo 服务器:
const { ApolloServer } = require('apollo-server');
const gql = require('graphql-tag');
const fetch = require('node-fetch');
const typeDefs = gql`
type Element {
id: ID!
name: String!
}
type Query {
elements: [Element]!
}
schema {
query: Query
}
`;
const resolvers = {
Query: {
async elements() {
const res = await fetch('https://reqres.in/api/users');
const { data } = await res.json();
const elements = data.map(({ id, first_name, last_name }) => ({ id, name: `${first_name} ${last_name}` }))
console.log('elements', elements);
return elements;
}
}
}
const server = new ApolloServer({
typeDefs,
resolvers
});
server.listen().then(({ url }) => {
console.log('server ready on ' + url);
});