简体   繁体   English

如何在React Native中将Apollo客户端正确连接到Redux

[英]How to properly hook up Apollo Client to Redux in React Native

I've been researching this for the past couple hours, and I am now extremely close to solving this. 在过去的几个小时中,我一直在研究这个问题,现在,我已经非常接近解决这个问题了。 Everything seems to be working now, but I do not have this.props.mutate in my component that has the Apollo HOC wrapping it. 现在一切似乎都可以正常工作,但是我的组件中没有Apollo HOC封装的this.props.mutate

I wired Apollo up as a reducer, so in my component, I would expect to see this.props.apollo.mutate available, but it's not there. 我将Apollo this.props.apollo.mutate为减速器,因此在我的组件中,我希望看到this.props.apollo.mutate可用,但它不存在。

This is all that seems to be provided currently: 目前似乎提供了这些:

console.log(this.props.apollo) console.log(this.props.apollo)

{"data":{},"optimistic":[],"reducerError":null}

Here is how it is hooked up: 这是它的连接方式:

./src/apolloClient.js ./src/apolloClient.js

import { AsyncStorage } from 'react-native'
import { ApolloClient, createNetworkInterface } from 'react-apollo'

const networkInterface = createNetworkInterface({
    uri: 'http://localhost:8000/graphql',
    opts: {
        credentials: 'same-origin',
        mode: 'cors'
    }
})

// networkInterface is half baked as I haven't got this far yet
networkInterface.use([{
    async applyMiddleware(req, next) {
        if (!req.options.headers) req.options.headers = {}
        const token = await AsyncStorage.getItem('token')
        req.options.headers.authorization = token ? token : null
        next()
    }
}])

const client = new ApolloClient({
    networkInterface,
    dataIdFromObject: (o) => o.id
})

export default client

./src/reducers.js ./src/reducers.js

import client from './apolloClient'

export default combineReducers({
    apollo: client.reducer(),
    nav: navReducer,
    signup: signupReducer,
    auth: loginReducer,
})

./src/App.js ./src/App.js

import store from './store'
import client from './apolloClient'

const Root = () => {
    return (
        <ApolloProvider store={store} client={client}>
            <RootNavigationStack />
        </ApolloProvider>
    )
}

export default Root

Oh, and here's the bottom of my Login component (also fairly half-baked): 哦,这是我的Login组件的底部(也是半熟):

export default compose(
    connect(mapStateToProps, {
        initiateLogin,
        toggleRememberMe
    }),
    withFormik({
        validate,
        validateOnBlur: true,
        validateOnChange: true,
        handleSubmit: ({ tel, password }, { props }) => {
            props.apollo.mutate({
                    variables: { tel, password }
                })
                .then((res) => {
                    alert(JSON.stringify(res))
                    //const token = res.data.login_mutation.token
                    //this.props.signinUser(token)
                    //client.resetStore()
                })
                .catch((err) => {
                    alert(JSON.stringify(err))
                    //this.props.authError(err)
                })
            //props.initiateLogin({ tel, password })
        }
    }),
    graphql(LOGIN_MUTATION, { options: { fetchPolicy: 'network-only' } })
)(LoginForm)

It feels like I need an action creator and to manually map it to my component. 感觉就像我需要一个动作创建者并将其手动映射到我的组件。 What do I need to do to run this loosely shown mutation LOGIN_MUTATION onSubmit? 我需要做什么来运行此松散显示的突变LOGIN_MUTATION onSubmit?

I'm currently confused by the fact this.props.apollo has Apollo's data in it, but there is no mutate . 目前,我对this.props.apollo包含Apollo的数据感到困惑,但是没有mutate

I don't see the solution here: http://dev.apollodata.com/react/mutations.html or maybe I do -- is this what I need to be looking at? 我在这里看不到解决方案: http : //dev.apollodata.com/react/mutations.html还是我愿意-这是我需要关注的吗?

const NewEntryWithData = graphql(submitRepository, {
  props: ({ mutate }) => ({
    submit: (repoFullName) => mutate({ variables: { repoFullName } }),
  }),
})(NewEntry)

I'd like to get it to the point where the component can call the mutation when it needs to. 我想让组件可以在需要时调用突变。 I'd also like it to be available on this.props.something so I can call it from Formik's handleSubmit function, but I am open to suggestions that enable the best declarative scalability. 我也希望它可以在this.props.something上使用,因此我可以从Formik的handleSubmit函数中调用它,但是我愿意接受能够实现最佳声明式可伸缩性的建议。

[edit] Here is the code that I am considering solved: [编辑]这是我正在考虑解决的代码:

./src/apolloClient.js ./src/apolloClient.js

This file was scrapped. 该文件已报废。

./src/reducers.js ./src/reducers.js

I removed the Apollo reducer and client reference. 我删除了Apollo减速器和客户端参考。

./src/App.js ./src/App.js

I put the Apollo Client inside the root component. 我将Apollo Client放在根组件中。 I got this technique from Nader Dabit's Medium post. 我从Nader Dabit的Medium帖子中获得了这项技术。 He illustrates this in a GitHub repo: 他在GitHub存储库中对此进行了说明:

Here is how it looks implemented: 这是实现的样子:

const Root = () => {
    const networkInterface = createNetworkInterface({
        uri: 'http://localhost:8000/graphql',
        opts: {
            credentials: 'same-origin',
            mode: 'cors'
        }
    })

    networkInterface.use([{
        async applyMiddleware(req, next) {
            try {
                if (!req.options.headers) req.options.headers = {}
                const token = await AsyncStorage.getItem('token')
                req.options.headers.authorization = token || null
                next()
            } catch (error) {
                next()
            }
        }
    }])

    const client = new ApolloClient({
        networkInterface,
        dataIdFromObject: (o) => o.id
    })

    return (
        <ApolloProvider store={store} client={client}>
            <RootNavigationStack />
        </ApolloProvider>
    )
}

export default Root

When you use compose , the order of your HOCs matters. 使用compose ,HOC的顺序很重要。 In your code, the props added by your first HOC ( connect ) are available to all the HOCs after it ( withFormik and graphql ). 在您的代码中,您的第一个HOC( connect )添加的道具对之后的所有HOC( withFormikgraphql )都是可用的。 The props added by withFormik are only available to graphql . withFormik添加的道具仅可用于graphql The props added by graphql are available to neither of the other two HOCs (just the component itself). graphql添加的道具对其他两个graphql均不可用(仅组件本身)。

If you rearrange the order to be compose -> graphql -> withFormik then you should have access to props.mutate inside withFormik . 如果您重新排列的顺序来compose - > graphql - > withFormik那么你应该有机会获得props.mutatewithFormik

Additionally, while you can integrate Redux and Apollo, all this does is prevent you from having two separate stores. 此外,虽然您可以集成Redux和Apollo,但这样做的全部目的是防止您拥有两个单独的商店。 Passing an existing store to Apollo is not going to change the API for the graphql HOC. 将现有商店传递给Apollo不会更改graphql HOC的API。 That means, regardless of what store you're using, when you correctly use the HOC, you will still get a data prop (or a mutate prop for mutations). 这意味着,无论您使用什么存储,当您正确使用HOC时,您仍然会获得data道具(或用于突变的mutate道具)。

While integrating Apollo with Redux does expose Apollo's store to your application, you should still use Apollo like normal. 虽然将Apollo与Redux集成确实将Apollo的商店公开给您的应用程序,但您仍应像平常一样使用Apollo。 In most cases, that means using the graphql HOC and utilizing data.props and data.mutate (or whatever you call those props if you pass in a name through options). 在大多数情况下,这意味着使用graphql HOC并利用data.propsdata.mutate (或通过选项传递名称的任何方式调用这些props)。

If you need to call the Apollo client directly, then use withApollo instead -- this exposes a client prop that you can then use. 如果您需要直接调用Apollo客户端,则改为使用withApollo -这会公开一个client道具,您可以随后使用它。 The apollo prop that connect exposes in your code is just the store used by Apollo -- it's not the actual client, so it will not have methods like mutate available to it. 在代码中公开的connect apollo道具只是阿波罗使用的商店-它不是实际的客户端,因此不会有像mutate这样的方法可用。 In most cases, though, there's no reason to go with withApollo over graphql . 但是,在大多数情况下,没有理由在withApollo上使用graphql

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM