我正在尝试实施apollo来提供我客户的表格组件。
import CustomersTable from 'components/Customer/CustomersTable';
此表必须是可过滤,可排序和分页的。我在MySQL表中有200.000个客户。这就是为什么在服务器端计算过滤器,排序和分页的原因。我需要查询单独客户的分页总数以及客户列表。
import GET_CUSTOMERS_PAGINATED_QUERY from './getCustomersPaginated.graphql';
import GET_CUSTOMERS_PAGINATED_COUNT_QUERY from './getCustomersPaginatedCount.graphql';
出乎意料的是,当filtersInput被更改时,重新获取功能被称为两次。第一次使用正确的新变量,第二次使用初始变量。因此,客户总数被覆盖。
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,
};
},
};
这两个查询由建议here组成(没有错误):
@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
返回:带有Symfony3的PHP 7和Youshido\GraphQLBundle
本月我开始做出反应,本月开始做阿波罗。 也许我没有像我应该那样使用重新提取,也许有更好的方法,或者可能有一个错误(我将apollo-client-preset从1.0.2更新到1.0.3而没有看到任何变化)。 也许Youshido方面的解决方案是能够在一个查询中获取客户的列表和客户的数量。
感谢您的帮助。
答案 0 :(得分:0)
在某些情况下,不需要重新获取功能。 感谢@stelmakh对此issue !!
的帮助我的新代码: 孩子:
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,
};
}
家长:
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>
);
}
}