如何在 React Native 中正确地将 Apollo Client 连接到 Redux

How to properly hook up Apollo Client to Redux in React Native

过去几个小时我一直在研究这个问题,现在我非常接近解决这个问题。现在一切似乎都在工作,但我的组件中没有 this.props.mutate 包装它的 Apollo HOC。

我将 Apollo 连接为减速器,因此在我的组件中,我希望看到 this.props.apollo.mutate 可用,但它不存在。

这是目前似乎提供的所有内容:

console.log(this.props.apollo)

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

连接方式如下:

./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

import client from './apolloClient'

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

./src/App.js

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

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

export default Root

哦,这是我的登录组件的底部(也是半成品):

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)

感觉我需要一个动作创建器并手动将其映射到我的组件。对于 运行 这个松散显示的突变 LOGIN_MUTATION onSubmit,我需要做什么?

我目前感到困惑的是 this.props.apollo 中有 Apollo 的数据,但没有 mutate

我在这里没有看到解决方案:http://dev.apollodata.com/react/mutations.html 或者我可能看到了 - 这是我需要查看的内容吗?

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

我想让它达到组件可以在需要时调用突变的程度。我还希望它在 this.props.something 上可用,这样我就可以从 Formik 的 handleSubmit 函数中调用它,但我愿意接受能够实现最佳声明式可伸缩性的建议。

[edit] 这是我正在考虑解决的代码:

./src/apolloClient.js

此文件已废弃。

./src/reducers.js

我删除了 Apollo reducer 和客户端参考。

./src/App.js

我将 Apollo Client 放在根组件中。我从 Nader Dabit 的 Medium post 那里获得了这项技术。他在 GitHub 回购中说明了这一点:

这是它的实现方式:

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

当您使用 compose 时,您的 HOC 的顺序很重要。在您的代码中,您的第一个 HOC (connect) 添加的 props 可用于其后的所有 HOC(withFormikgraphql)。 withFormik添加的道具仅graphql可用。 graphql 添加的 props 对其他两个 HOC 都不可用(只是组件本身)。

如果您将顺序重新排列为 compose -> graphql -> withFormik 那么您应该可以访问 withFormik 中的 props.mutate

此外,虽然您 可以 集成 Redux 和 Apollo,但这只会阻止您拥有两个独立的商店。将现有商店传递给 Apollo 不会更改 graphql HOC 的 API。这意味着,无论您使用的是什么商店,当您正确使用 HOC 时,您仍然会得到一个 data 道具(或 mutate 道具用于突变)。

虽然将 Apollo 与 Redux 集成确实会向您的应用程序公开 Apollo 的商店,但您仍应像往常一样使用 Apollo。 在大多数情况下,这意味着使用 graphql HOC并利用 data.propsdata.mutate(或者如果您通过选项传入名称,则可以调用这些道具)。

如果您需要直接调用 Apollo 客户端,请改用 withApollo——这会公开一个 client 道具,您可以随后使用它。 connect 在您的代码中公开的 apollo 道具只是 Apollo 使用的商店——它不是实际的客户端,因此它不会有像 mutate 这样的可用方法。但是,在大多数情况下,没有理由使用 withApollo 而不是 graphql