问题
Apollo client (2.6.3) with react. Is it possible to fetch data in a method of a class component? I'm building a global search component and I want to fetch data only when 3rd (and each subsequent) character is typed. Right now it is implemented with fetch api but I want to switch to apollo client and graphql api.
Until this moment I haven't gotten any problems with apollo client API cause I use
<Query/>
component.
I've tried to use new hooks api but it turned out that useLazyQuery() can be used only in a function component (rules of hooks).
This is what I have done so far. I know that component is messy and I'm open to suggestions. This is my first react app.
import React, { Component } from "react";
import PropTypes from "prop-types";
import { Select, Icon, Button } from "antd";
import { es } from "../../../utils/queries";
import { useLazyQuery } from "@apollo/react-hooks";
const { Option, OptGroup } = Select;
class GlobalSearch extends Component {
constructor(props) {
super(props);
this.searchInput = React.createRef();
}
state = {
data: [],
value: undefined,
display: false
};
componentDidMount() {
document.addEventListener("click", this.onClickOutside);
}
generateOptions(data) {
return data.map(d => {
if (d._index === "cases") {
d.label = (
<div>
<Icon style={{ fontSize: "18px" }} type="tool" />
<span style={{ color: "#183247" }}>
{d._source.number + d._source.serialNumber}
</span>
</div>
);
} else if (d._index === "items") {
d.label = (
<div>
<Icon style={{ fontSize: "18px" }} type="barcode-o" />
<span style={{ color: "#183247" }}>{d._source.name}</span>
</div>
);
} else if (d._index === "people") {
d.label = (
<div>
<Icon
type="user"
style={{ fontSize: "18px", float: "left", marginTop: "3px" }}
/>
<div style={{ marginLeft: "26px" }}>
<span style={{ color: "#183247" }}>
{" "}
<div>{d._source.name + " " + d._source.surname}</div>
</span>
<div>{d._source.email}</div>
</div>
</div>
);
} else if (d._index === "counterparties") {
d.label = (
<div>
<Icon style={{ fontSize: "18px" }} type="shop" />
<span style={{ color: "#183247" }}>{d._source.name}</span>
</div>
);
} else {
d.label = "undefined";
}
return d;
});
}
//group data according to type of the search result (index e.g. cases, items, contacts)
setData = es_data => {
const data = {};
const map = new Map();
for (const item of es_data) {
if (!map.has(item._index)) {
map.set(item._index);
data[item._index] = [];
}
data[item._index].push(item);
}
this.setState({ data: data });
};
handleSearch = value => {
if (value.length > 2) {
//tutaj wyszukujemy dane na serwerze a wyniki callbackiem przesyłamy do state.data[]
//response.json() calls mixin methods from body
const host = window.location.hostname
// const { loading, data } = useLazyQuery(es(value));
// if (loading) return undefined;
// if (data) {
// this.setData(this.generateOptions(data));
// }
fetch(`http://${host}:3000/api/es?searchString=${value}`)
.then(response => response.json())
.then(es_data => {
this.setData(this.generateOptions(es_data));
});
}
};
handleChange = value => {
//przy kazdym wpisanym znaku aktualizuj wartosc pola
this.setState({ value });
};
handleSelect = (key, option) => {
console.log(key);
console.log(option);
};
handleBlur = e => {
this.setState({ display: false, value: undefined, data: [] });
};
onClick = () => {
this.setState({ display: !this.state.display });
};
getSearchField(options) {
if (this.state.display) {
return (
<Select
id="global-search-field"
optionLabelProp="label"
showSearch
value={this.state.value}
placeholder={"search..."}
style={{ display: this.state.display, width: "350px" }}
defaultActiveFirstOption={true}
showArrow={false}
filterOption={false}
onSearch={this.handleSearch}
onChange={this.handleChange}
onSelect={this.handleSelect}
notFoundContent={"nothing here..."}
onBlur={this.handleBlur}
autoFocus={true}
showAction={["focus"]}
dropdownClassName="global-search-dropdown"
>
{options}
</Select>
);
}
}
render() {
//generate options for each group (index)
const options = Object.keys(this.state.data).map(d => (
<OptGroup label={d}>
{this.state.data[d].map(d => (
<Option
className={d._index}
type={d._index}
key={d._id}
label={d.label}
>
<div>{d.label}</div>
</Option>
))}
</OptGroup>
));
return (
<span>
{this.getSearchField(options)}
<Button
id="global-search"
shape="circle"
icon="search"
onClick={this.onClick}
/>
</span>
);
}
}
export default GlobalSearch;
回答1:
Apollo Client offers a Promise-based API that provides more imperative control over when/where your queries/mutations are run. Here's an example from their docs:
client
.query({
query: gql`
query GetLaunch {
launch(id: 56) {
id
mission {
name
}
}
}
`,
variables: { ... }
})
.then(result => console.log(result));
You can import your client and use this pattern in any method or function like any other async operation using Promises.
来源:https://stackoverflow.com/questions/57874784/fetching-query-in-method-of-a-class-component