React-apollo v2 - Youshido GraphQlBundle - 同时重新获取两个查询
React-apollo v2 - Youshido GraphQlBundle - refetch two queries simultaneously
我正在尝试实施 apollo 来满足我客户的 table 组件。
import CustomersTable from 'components/Customer/CustomersTable';
这个 table 必须是可过滤的,sortable 和分页的。我在 MySQL table 中有 200.000 位客户。这就是为什么过滤器、排序和分页是在服务器端计算的。我需要查询 单独 分页的客户总数,以及客户列表。
import GET_CUSTOMERS_PAGINATED_QUERY from './getCustomersPaginated.graphql';
import GET_CUSTOMERS_PAGINATED_COUNT_QUERY from './getCustomersPaginatedCount.graphql';
出乎意料的是,当 filtersInput 发生变化时,refetch 函数被调用 两次 。第一次使用正确的新变量,第二次使用 初始变量 。所以客户总数被覆盖。
const initialFilters = {
filterId: null,
filterSiren: null,
filterName: null,
filterEmail: null,
};
const getCustomersPaginatedCountOptions = {
name: 'customersPaginatedCount',
options() {
return {
variables: {
...initialFilters,
},
fetchPolicy: 'network-only',
};
},
props({ customersPaginatedCount }) {
return {
customersPaginatedCount: customersPaginatedCount,
};
},
};
const getCustomersPaginatedOptions = {
name: 'customersPaginated',
options({ offset, limit }) {
return {
variables: {
offset: offset,
limit: limit,
...initialFilters,
},
fetchPolicy: 'network-only',
};
},
props({ customersPaginated }) {
return {
customersPaginated: customersPaginated,
};
},
};
这两个查询由建议组成(没有错误):
@compose(
graphql(GET_CUSTOMERS_PAGINATED_QUERY, getCustomersPaginatedOptions),
graphql(GET_CUSTOMERS_PAGINATED_COUNT_QUERY, getCustomersPaginatedCountOptions),
)
export default class CustomersTableContainer extends React.PureComponent {
state = {
offset: this.props.offset,
limit: this.props.limit,
pageSize: 10,
currentPage: 0,
filters: initialFilters,
currentOnFilterChangeTimeoutID: null,
};
constructor(props) {
super(props);
this.onCurrentPageChange = this.onCurrentPageChange.bind(this);
this.onFiltersChange = this.onFiltersChange.bind(this);
}
onCurrentPageChange(newPage) {
const { customersPaginated } = this.props;
const { limit, filters } = this.state;
customersPaginated.refetch({
offset: newPage * limit,
...filters,
});
this.setState({ currentPage: newPage });
}
onFiltersChange(args) {
const { customersPaginated, customersPaginatedCount } = this.props;
const { limit } = this.state;
const newFilters = Object.assign({}, initialFilters);
for ( const i in args ) {
newFilters['filter' + ucfirst(args[i].columnName)] = args[i].value;
}
customersPaginated.refetch({
offset: 0 * limit,
...newFilters,
});
// --- >> THE REFETCH FUNCTION IS TRIGGERED TWICE HERE ! << ---
customersPaginatedCount.refetch({
...newFilters,
});
// here 'test' is displayed once, so onFiltersChange is called once too as expected
console.log('test');
this.setState({
currentPage: 0,
filters: newFilters,
});
}
render () {
const { customersPaginated, customersPaginatedCount } = this.props;
const { currentPage, pageSize } = this.state;
if (customersPaginated.error) console.error( customersPaginated.error );
if (customersPaginatedCount.error) console.error( customersPaginatedCount.error );
return (
<div>
{(customersPaginated.error || customersPaginatedCount.error) && (
<Typography color="error" gutterBottom>
Une erreur est survenue.
</Typography>
)}
<div>
<CustomersTable
customers={customersPaginated.customersPaginated}
currentPage={currentPage}
onCurrentPageChange={this.onCurrentPageChange}
onFiltersChange={this.onFiltersChange}
pageSize={pageSize}
totalCount={customersPaginatedCount.customersPaginatedCount || 0}
/>
{(customersPaginated.loading || customersPaginatedCount.loading) && <Loading />}
</div>
</div>
);
}
static propTypes = {
customersPaginated: PropTypes.object.isRequired,
customersPaginatedCount: PropTypes.object.isRequired,
offset: PropTypes.number.isRequired,
limit: PropTypes.number.isRequired,
};
}
我的控制台以预期的行为登录组件加载:
{variables: {filterId: null, filterSiren: null, filterName: null, filterEmail: null}, operationName: "getCustomersPaginatedCount"
{variables: {filterId: null, filterSiren: null, filterName: null, filterEmail: null}, operationName: "getCustomersPaginated"
我的控制台以 意外 行为记录过滤器输入更改:
{variables: {filterId: null, filterSiren: null, filterName: "example of customer name", filterEmail: null}, operationName: "getCustomersPaginated"
{variables: {filterId: null, filterSiren: null, filterName: "example of customer name", filterEmail: null}, operationName: "getCustomersPaginatedCount"
{variables: {filterId: null, filterSiren: null, filterName: null, filterEmail: null}, operationName: "getCustomersPaginatedCount"
getCustomersPaginated.graphql :
query getCustomersPaginated(
$filterId: Int,
$filterSiren: String,
$filterName: String,
$filterEmail: String,
$offset: Int,
$limit: Int
) {
customersPaginated(
filterId: $filterId,
filterSiren: $filterSiren,
filterName: $filterName,
filterEmail: $filterEmail,
offset: $offset,
limit: $limit
) {
id
name
siren
email
activity {
id
name
shortName
code
}
salesFollower {
id
username
firstname
lastname
email
initials
enabled
}
customerGroup {
id
name
code
enabled
}
coreBusiness {
id
name
codeApe
codeNaf
}
}
}
getCustomersPaginatedCount.graphql :
query getCustomersPaginatedCount(
$filterId: Int,
$filterSiren: String,
$filterName: String,
$filterEmail: String
) {
customersPaginatedCount(
filterId: $filterId,
filterSiren: $filterSiren,
filterName: $filterName,
filterEmail: $filterEmail,
)
}
我的环境:
前面 : reactjs 与 react-apollo
返回 : PHP 7 with Symfony3 and Youshido\GraphQLBundle
我今年开始反应,这个月开始阿波罗。
也许我没有像我应该的那样使用 refetch,也许有更好的方法,或者可能有一个错误(我将 apollo-client-preset 从 1.0.2 更新到 1.0.3,但没有看到任何变化)。
也许 Youshido 有一个解决方案,可以在一个查询中获取客户列表和客户数量。
感谢您的帮助。
在某些情况下,refetch 函数不是必需的。
感谢@stelmakh 在这方面的帮助 issue !!
我的新代码:
Child :
import React from 'react';
import PropTypes from 'prop-types';
import { compose, graphql } from 'react-apollo';
import { ucfirst } from 'utils/string';
import CustomersTable from 'components/Customer/CustomersTable';
import Typography from 'material-ui/Typography';
import Loading from 'components/Loading/Loading';
import GET_CUSTOMERS_PAGINATED_QUERY from './getCustomersPaginated.graphql';
import GET_CUSTOMERS_PAGINATED_COUNT_QUERY from './getCustomersPaginatedCount.graphql';
const getCustomersPaginatedCountOptions = {
name: 'customersPaginatedCount',
options({ variables }) {
return {
variables: variables,
fetchPolicy: 'network-only',
};
},
props({ customersPaginatedCount }) {
return { customersPaginatedCount: customersPaginatedCount };
},
};
const getCustomersPaginatedOptions = {
name: 'customersPaginated',
options({ variables }) {
return {
variables: variables,
fetchPolicy: 'network-only',
};
},
props({ customersPaginated }) {
return { customersPaginated: customersPaginated };
},
};
@compose(
graphql(GET_CUSTOMERS_PAGINATED_QUERY, getCustomersPaginatedOptions),
graphql(GET_CUSTOMERS_PAGINATED_COUNT_QUERY, getCustomersPaginatedCountOptions),
)
export default class CustomersTableContainer extends React.PureComponent {
state = {
currentOnFilterChangeTimeoutID: null,
};
constructor(props) {
super(props);
this.onCurrentPageChange = this.onCurrentPageChange.bind(this);
this.onSortingChange = this.onSortingChange.bind(this);
this.onFiltersChange = this.onFiltersChange.bind(this);
}
onCurrentPageChange(newPage) {
const { onChange, variables } = this.props;
onChange({
currentPage: newPage,
'offset': newPage * variables.limit,
});
}
onFiltersChange(args) {
clearTimeout(this.state.currentOnFilterChangeTimeoutID);
const newCurrentOnFilterChangeTimeoutID = setTimeout(() => {
const { onChange, variables } = this.props;
const newVariables = Object.assign({}, variables);
if (args.length > 0) {
for ( const i in args ) {
newVariables['filter' + ucfirst(args[i].columnName)] = args[i].value;
}
} else {
for ( const i in newVariables ) {
if (i.substr(0, 6) === 'filter') newVariables[i] = null;
}
}
onChange({
...newVariables,
'currentPage': 0,
'offset': 0 * variables.limit,
});
}, 1000);
this.setState({ currentOnFilterChangeTimeoutID: newCurrentOnFilterChangeTimeoutID });
}
render () {
const { variables, customersPaginated, customersPaginatedCount } = this.props;
if (customersPaginated.error) console.error( customersPaginated.error );
if (customersPaginatedCount.error) console.error( customersPaginatedCount.error );
return (
<div>
{(customersPaginated.error || customersPaginatedCount.error) && (
<Typography color="error" gutterBottom>
Une erreur est survenue.
</Typography>
)}
<div>
<CustomersTable
customers={customersPaginated.customersPaginated}
currentPage={variables.currentPage}
onCurrentPageChange={this.onCurrentPageChange}
onSortingChange={this.onSortingChange}
onFiltersChange={this.onFiltersChange}
pageSize={variables.pageSize}
totalCount={customersPaginatedCount.customersPaginatedCount || 0}
/>
{(customersPaginated.loading || customersPaginatedCount.loading) && <Loading />}
</div>
</div>
);
}
static propTypes = {
customersPaginated: PropTypes.object.isRequired,
customersPaginatedCount: PropTypes.object.isRequired,
variables: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
};
}
Parent :
import React from 'react';
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';
import AddIcon from 'material-ui-icons/Add';
import CustomersTableContainer from 'containers/Customer/CustomersTableContainer';
export default class CustomersPage extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
customersTableVariables: {
filterId: null,
filterSiren: null,
filterName: null,
filterEmail: null,
pageSize: 10,
currentPage: 0,
offset: 0,
limit: 10,
},
};
this.onCustomersChange = this.onCustomersChange.bind(this);
}
onCustomersChange (newVariables) {
this.setState({
customersTableVariables: Object.assign({}, this.state.customersTableVariables, newVariables)
});
}
render () {
const { customersTableVariables } = this.state;
return (
<div>
<Typography align="right">
<Button fab color="primary" aria-label="add" href="/customer/new">
<AddIcon />
</Button>
</Typography>
<Typography type="title" gutterBottom>
Clients/Prospects
</Typography>
<CustomersTableContainer variables={customersTableVariables} onChange={this.onCustomersChange} />
</div>
);
}
}
我正在尝试实施 apollo 来满足我客户的 table 组件。
import CustomersTable from 'components/Customer/CustomersTable';
这个 table 必须是可过滤的,sortable 和分页的。我在 MySQL table 中有 200.000 位客户。这就是为什么过滤器、排序和分页是在服务器端计算的。我需要查询 单独 分页的客户总数,以及客户列表。
import GET_CUSTOMERS_PAGINATED_QUERY from './getCustomersPaginated.graphql';
import GET_CUSTOMERS_PAGINATED_COUNT_QUERY from './getCustomersPaginatedCount.graphql';
出乎意料的是,当 filtersInput 发生变化时,refetch 函数被调用 两次 。第一次使用正确的新变量,第二次使用 初始变量 。所以客户总数被覆盖。
const initialFilters = {
filterId: null,
filterSiren: null,
filterName: null,
filterEmail: null,
};
const getCustomersPaginatedCountOptions = {
name: 'customersPaginatedCount',
options() {
return {
variables: {
...initialFilters,
},
fetchPolicy: 'network-only',
};
},
props({ customersPaginatedCount }) {
return {
customersPaginatedCount: customersPaginatedCount,
};
},
};
const getCustomersPaginatedOptions = {
name: 'customersPaginated',
options({ offset, limit }) {
return {
variables: {
offset: offset,
limit: limit,
...initialFilters,
},
fetchPolicy: 'network-only',
};
},
props({ customersPaginated }) {
return {
customersPaginated: customersPaginated,
};
},
};
这两个查询由建议组成
@compose(
graphql(GET_CUSTOMERS_PAGINATED_QUERY, getCustomersPaginatedOptions),
graphql(GET_CUSTOMERS_PAGINATED_COUNT_QUERY, getCustomersPaginatedCountOptions),
)
export default class CustomersTableContainer extends React.PureComponent {
state = {
offset: this.props.offset,
limit: this.props.limit,
pageSize: 10,
currentPage: 0,
filters: initialFilters,
currentOnFilterChangeTimeoutID: null,
};
constructor(props) {
super(props);
this.onCurrentPageChange = this.onCurrentPageChange.bind(this);
this.onFiltersChange = this.onFiltersChange.bind(this);
}
onCurrentPageChange(newPage) {
const { customersPaginated } = this.props;
const { limit, filters } = this.state;
customersPaginated.refetch({
offset: newPage * limit,
...filters,
});
this.setState({ currentPage: newPage });
}
onFiltersChange(args) {
const { customersPaginated, customersPaginatedCount } = this.props;
const { limit } = this.state;
const newFilters = Object.assign({}, initialFilters);
for ( const i in args ) {
newFilters['filter' + ucfirst(args[i].columnName)] = args[i].value;
}
customersPaginated.refetch({
offset: 0 * limit,
...newFilters,
});
// --- >> THE REFETCH FUNCTION IS TRIGGERED TWICE HERE ! << ---
customersPaginatedCount.refetch({
...newFilters,
});
// here 'test' is displayed once, so onFiltersChange is called once too as expected
console.log('test');
this.setState({
currentPage: 0,
filters: newFilters,
});
}
render () {
const { customersPaginated, customersPaginatedCount } = this.props;
const { currentPage, pageSize } = this.state;
if (customersPaginated.error) console.error( customersPaginated.error );
if (customersPaginatedCount.error) console.error( customersPaginatedCount.error );
return (
<div>
{(customersPaginated.error || customersPaginatedCount.error) && (
<Typography color="error" gutterBottom>
Une erreur est survenue.
</Typography>
)}
<div>
<CustomersTable
customers={customersPaginated.customersPaginated}
currentPage={currentPage}
onCurrentPageChange={this.onCurrentPageChange}
onFiltersChange={this.onFiltersChange}
pageSize={pageSize}
totalCount={customersPaginatedCount.customersPaginatedCount || 0}
/>
{(customersPaginated.loading || customersPaginatedCount.loading) && <Loading />}
</div>
</div>
);
}
static propTypes = {
customersPaginated: PropTypes.object.isRequired,
customersPaginatedCount: PropTypes.object.isRequired,
offset: PropTypes.number.isRequired,
limit: PropTypes.number.isRequired,
};
}
我的控制台以预期的行为登录组件加载:
{variables: {filterId: null, filterSiren: null, filterName: null, filterEmail: null}, operationName: "getCustomersPaginatedCount"
{variables: {filterId: null, filterSiren: null, filterName: null, filterEmail: null}, operationName: "getCustomersPaginated"
我的控制台以 意外 行为记录过滤器输入更改:
{variables: {filterId: null, filterSiren: null, filterName: "example of customer name", filterEmail: null}, operationName: "getCustomersPaginated"
{variables: {filterId: null, filterSiren: null, filterName: "example of customer name", filterEmail: null}, operationName: "getCustomersPaginatedCount"
{variables: {filterId: null, filterSiren: null, filterName: null, filterEmail: null}, operationName: "getCustomersPaginatedCount"
getCustomersPaginated.graphql :
query getCustomersPaginated(
$filterId: Int,
$filterSiren: String,
$filterName: String,
$filterEmail: String,
$offset: Int,
$limit: Int
) {
customersPaginated(
filterId: $filterId,
filterSiren: $filterSiren,
filterName: $filterName,
filterEmail: $filterEmail,
offset: $offset,
limit: $limit
) {
id
name
siren
email
activity {
id
name
shortName
code
}
salesFollower {
id
username
firstname
lastname
email
initials
enabled
}
customerGroup {
id
name
code
enabled
}
coreBusiness {
id
name
codeApe
codeNaf
}
}
}
getCustomersPaginatedCount.graphql :
query getCustomersPaginatedCount(
$filterId: Int,
$filterSiren: String,
$filterName: String,
$filterEmail: String
) {
customersPaginatedCount(
filterId: $filterId,
filterSiren: $filterSiren,
filterName: $filterName,
filterEmail: $filterEmail,
)
}
我的环境:
前面 : reactjs 与 react-apollo
返回 : PHP 7 with Symfony3 and Youshido\GraphQLBundle
我今年开始反应,这个月开始阿波罗。 也许我没有像我应该的那样使用 refetch,也许有更好的方法,或者可能有一个错误(我将 apollo-client-preset 从 1.0.2 更新到 1.0.3,但没有看到任何变化)。 也许 Youshido 有一个解决方案,可以在一个查询中获取客户列表和客户数量。
感谢您的帮助。
在某些情况下,refetch 函数不是必需的。 感谢@stelmakh 在这方面的帮助 issue !!
我的新代码: Child :
import React from 'react';
import PropTypes from 'prop-types';
import { compose, graphql } from 'react-apollo';
import { ucfirst } from 'utils/string';
import CustomersTable from 'components/Customer/CustomersTable';
import Typography from 'material-ui/Typography';
import Loading from 'components/Loading/Loading';
import GET_CUSTOMERS_PAGINATED_QUERY from './getCustomersPaginated.graphql';
import GET_CUSTOMERS_PAGINATED_COUNT_QUERY from './getCustomersPaginatedCount.graphql';
const getCustomersPaginatedCountOptions = {
name: 'customersPaginatedCount',
options({ variables }) {
return {
variables: variables,
fetchPolicy: 'network-only',
};
},
props({ customersPaginatedCount }) {
return { customersPaginatedCount: customersPaginatedCount };
},
};
const getCustomersPaginatedOptions = {
name: 'customersPaginated',
options({ variables }) {
return {
variables: variables,
fetchPolicy: 'network-only',
};
},
props({ customersPaginated }) {
return { customersPaginated: customersPaginated };
},
};
@compose(
graphql(GET_CUSTOMERS_PAGINATED_QUERY, getCustomersPaginatedOptions),
graphql(GET_CUSTOMERS_PAGINATED_COUNT_QUERY, getCustomersPaginatedCountOptions),
)
export default class CustomersTableContainer extends React.PureComponent {
state = {
currentOnFilterChangeTimeoutID: null,
};
constructor(props) {
super(props);
this.onCurrentPageChange = this.onCurrentPageChange.bind(this);
this.onSortingChange = this.onSortingChange.bind(this);
this.onFiltersChange = this.onFiltersChange.bind(this);
}
onCurrentPageChange(newPage) {
const { onChange, variables } = this.props;
onChange({
currentPage: newPage,
'offset': newPage * variables.limit,
});
}
onFiltersChange(args) {
clearTimeout(this.state.currentOnFilterChangeTimeoutID);
const newCurrentOnFilterChangeTimeoutID = setTimeout(() => {
const { onChange, variables } = this.props;
const newVariables = Object.assign({}, variables);
if (args.length > 0) {
for ( const i in args ) {
newVariables['filter' + ucfirst(args[i].columnName)] = args[i].value;
}
} else {
for ( const i in newVariables ) {
if (i.substr(0, 6) === 'filter') newVariables[i] = null;
}
}
onChange({
...newVariables,
'currentPage': 0,
'offset': 0 * variables.limit,
});
}, 1000);
this.setState({ currentOnFilterChangeTimeoutID: newCurrentOnFilterChangeTimeoutID });
}
render () {
const { variables, customersPaginated, customersPaginatedCount } = this.props;
if (customersPaginated.error) console.error( customersPaginated.error );
if (customersPaginatedCount.error) console.error( customersPaginatedCount.error );
return (
<div>
{(customersPaginated.error || customersPaginatedCount.error) && (
<Typography color="error" gutterBottom>
Une erreur est survenue.
</Typography>
)}
<div>
<CustomersTable
customers={customersPaginated.customersPaginated}
currentPage={variables.currentPage}
onCurrentPageChange={this.onCurrentPageChange}
onSortingChange={this.onSortingChange}
onFiltersChange={this.onFiltersChange}
pageSize={variables.pageSize}
totalCount={customersPaginatedCount.customersPaginatedCount || 0}
/>
{(customersPaginated.loading || customersPaginatedCount.loading) && <Loading />}
</div>
</div>
);
}
static propTypes = {
customersPaginated: PropTypes.object.isRequired,
customersPaginatedCount: PropTypes.object.isRequired,
variables: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
};
}
Parent :
import React from 'react';
import Typography from 'material-ui/Typography';
import Button from 'material-ui/Button';
import AddIcon from 'material-ui-icons/Add';
import CustomersTableContainer from 'containers/Customer/CustomersTableContainer';
export default class CustomersPage extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
customersTableVariables: {
filterId: null,
filterSiren: null,
filterName: null,
filterEmail: null,
pageSize: 10,
currentPage: 0,
offset: 0,
limit: 10,
},
};
this.onCustomersChange = this.onCustomersChange.bind(this);
}
onCustomersChange (newVariables) {
this.setState({
customersTableVariables: Object.assign({}, this.state.customersTableVariables, newVariables)
});
}
render () {
const { customersTableVariables } = this.state;
return (
<div>
<Typography align="right">
<Button fab color="primary" aria-label="add" href="/customer/new">
<AddIcon />
</Button>
</Typography>
<Typography type="title" gutterBottom>
Clients/Prospects
</Typography>
<CustomersTableContainer variables={customersTableVariables} onChange={this.onCustomersChange} />
</div>
);
}
}