Reputation: 590
The following React component works correctly, I'm able to query a GraphQL endpoint using Apollo-React. In this specific case I'm using an Apollo-React's compose
function, to add several queries in the same component.
I would like to inject dynamically, in the HOC variables
field, the userId.
Is there a way to do it ? Because simply calling the function getUser()
doesn't seems to works, I get only a promise.
class AllCardsScreen extends Component {
state = {
query: '',
userCardsById: [],
userId:'',
loading: false,
};
getUser = async () => {
await Auth.currentUserInfo()
.then((data) => {
this.setState({ userId: data.attributes.sub});
})
.catch(error => console.log(`Error: ${error.message}`));
};
render() {
return (
<View style={styles.container}>
<FlatList
data={this.props.userCardsList}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
keyboardShouldPersistTaps="handled"
/>
</View>
);
}
export default compose(
graphql(ListCards, {
options: (props) => ({
fetchPolicy: 'cache-and-network',
variables: { userId : '18e946df-d3de-49a8-98b3-8b6d74dfd652'}
}),
props: (props) => ({
userCardsList: props.data.userCardsList ? props.data.userCardsList.userCards : [],
}),
})
)(AllCardsScreen);
EDIT:
This is the final working version based also on Daniel suggestion (Thx Daniel), with an API asyncronous call injected inside the HOC Apollo-graphQl enhancer. I had to call the data.props.refetch()
function to update the variables
value.
class AuthWrapper extends React.Component {
state = {
userId: null,
}
async componentDidMount () {
const data = await Auth.currentUserInfo()
this.setState({ userId: data.attributes.sub})
}
render () {
return this.state.userId
? <AllCardsScreen {...this.state} {...this.props}/>
: null
}
}
class AllCardsScreen extends Component {
state = {
query: '',
userCardsById: [],
userId:'',
loading: false,
};
componentDidMount() {
this.props.dataRefetch(this.props.userId)
SplashScreen.hide();
}
render() {
return (
<View style={styles.container}>
<FlatList
data={this.props.userCardsList}
keyExtractor={this.keyExtractor}
renderItem={this.renderItem}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
keyboardShouldPersistTaps="handled"
/>
</View>
);
}
export default compose(
graphql(ListCards, {
options: (props) => ({
fetchPolicy: 'cache-and-network',
variables: { userId : ''}
}),
props: (props) => ({
userCardsList: props.data.userCardsList ? props.data.userCardsList.userCards : [],
dataRefetch: (userId) => {
props.data.refetch({userId})
},
}),
})
)(AllCardsScreen);
Upvotes: 2
Views: 1583
Reputation: 84667
The graphql
HOC only uses props -- since it's effectively just wrapping the component it's passed, it won't have access to that component's state. There's also not a way to fetch data asynchronously inside the HOC's configuration.
The simplest solution is to just lift the state into either an existing parent component, or a new component that would wrap your existing one. For example:
class WrapperComponent extends Component {
state = {
userId: null,
}
async componentDidMount () {
const data = await Auth.currentUserInfo()
this.setState({ userId: data.attributes.sub})
}
render () {
// May want to render nothing or a loading indicator if userId is null
return <AllCardsScreen userId={this.state.userId} {...otherProps} />
}
}
Alternatively, you can create your own HOC to encapsulate the same logic:
function authHOC(WrappedComponent) {
return class AuthWrapper extends React.Component {
state = {
userId: null,
}
async componentDidMount () {
const data = await Auth.currentUserInfo()
this.setState({ userId: data.attributes.sub})
}
render () {
return this.state.userId
? <WrappedComponent {...this.props} userId={this.state.userId} />
: null
}
}
}
Upvotes: 2