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

Posted

技术标签:

【中文标题】如何在 React Native 中正确地将 Apollo 客户端连接到 Redux【英文标题】:How to properly hook up Apollo Client to Redux in React Native 【发布时间】:2018-04-02 21:00:00 【问题描述】:

过去几个小时我一直在研究这个问题,现在我非常接近解决这个问题。现在似乎一切正常,但我的组件中没有 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 函数中调用它,但我愿意接受能够实现最佳声明式可伸缩性的建议。

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

./src/apolloClient.js

此文件已废弃。

./src/reducers.js

我删除了 Apollo reducer 和客户端引用。

./src/App.js

我将 Apollo Client 放在根组件中。我从 Nader Dabit 的 Medium 帖子中获得了这项技术。他在 GitHub 存储库中对此进行了说明:

https://github.com/react-native-training/apollo-graphql-mongodb-react-native https://medium.com/react-native-training/react-native-with-apollo-part-2-apollo-client-8b4ad4915cf5

下面是它的实现方式:

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

【问题讨论】:

我认为options.props 是我需要的。我目前正在研究它。 对于将来看到此内容的任何人,请阅读有关 AsyncStorage 的 React Native 文档。您应该创建自己的实例。不要直接使用它,因为它具有全局元素。我的代码显示是这样的,但这是因为代码未完成。 【参考方案1】:

当您使用compose 时,您的 HOC 的顺序很重要。在您的代码中,您的第一个 HOC (connect) 添加的道具可供其后的所有 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 的 store 暴露给您的应用程序,但您仍然应该像往常一样使用 Apollo。 在大多数情况下,这意味着使用 graphql HOC 并利用 data.props 和 @ 987654339@(或者如果你通过选项传入一个名称,那么你称之为这些道具的任何东西)。

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

【讨论】:

很好,谢谢。考虑到 compose 实际在做什么,这是完全合理的。谢谢你的帖子;这非常有帮助。 你是说我可以在我的根组件中以相同的方式传递客户端,但只需省略将其连接到 Redux 的步骤? (很确定我的网络应用程序就是这样做的)。 大声笑,我只是自欺欺人。在我提交表单之前,this.props 中实际上没有任何可见的内容。我从 Redux 中删除了 Apollo,所以现在它与我的 Web 应用程序完全匹配,我刚刚收到一个网络请求错误,因为我还没有创建用户,所以它肯定可以工作。再次,您的帖子非常有帮助,谢谢。我将更新我的帖子以说明已解决的代码(对于任何未来的搜索者)。

以上是关于如何在 React Native 中正确地将 Apollo 客户端连接到 Redux的主要内容,如果未能解决你的问题,请参考以下文章

如何在 react-native for android 中更改应用程序图标背景颜色

React-native IOS:网络请求失败

需要的建议:如何正确地将 React 连接到 MongoDB

如何使用 react-native-firebase v5 正确设置前台通知?

React Native - 如何正确验证文本输入?

如何在 React Native 中正确旋转和翻译文本 90 度?