Why should I use ApolloConsumer instead of importing directly the client in my module ?
From the doc I should do somthing like :
// Module A.js initiate client
const client = new ApolloClient({
// init cache, links, typeDefs...
});
export default client;
// Module index.jsx
import client from 'A';
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById('root'));
// Any other component not using Query or Mutation
const Other = () => (
<ApolloConsumer>
{
client => {
// use client
}
}
</ApolloConsumer>);
But why not just import client without ApolloConsumer ?
// Module OtherBis
import client from 'A';
const AltOther () => {
// do something with client
return <div></div>;
};
Probably for the same reasons why you shouldn't import store directly:
Similarly, while you can reference your store instance by importing it directly, this is not a recommended pattern in Redux. If you create a store instance and export it from a module, it will become a singleton. This means it will be harder to isolate a Redux app as a component of a larger app, if this is ever necessary, or to enable server rendering, because on the server you want to create separate store instances for every request.
In my opinion, ApolloConsumer component is created for support JSX just like react-relay for relay. It is not necessary. Actually I have never used the ApolloConsumer. Moreover there are hooks(eg. useQuery, useMutation, useSubscription) which can do everything. They just make a tool. Whether use it or not is up to you.
Related
i'm working on a project, and i'm using apollo/client, graphql in react, and for the global state management, i love using redux, but, before you say to me, why the hell am i using redux for, the reason for it, it's because i have to handle the data of the user in the login/register so i can put it in the localStorage, but not only for that, i'm quite sure i'll have to handle more data in my project so i'll put it in my store.
So, my question literally is, how to put the redux with apollo client, so i can use graphql to get data easily and if i have to store data, i can do it normally
i saw this way in the docs, but it didn't work for me, and the browser got mad at me and gave the error of, no Provider provided in the redux setup
import React from "react";
import App from "./App";
import { createStore } from "redux";
import reducer from "./reducer";
import {
createHttpLink,
InMemoryCache,
ApolloProvider,
ApolloClient
} from "#apollo/client";
const httpLink = createHttpLink({
uri: "http://localhost:5000"
});
const client = new ApolloClient({
link: httpLink,
cache: new InMemoryCache()
});
const store = createStore(reducer);
export default (
<ApolloProvider client={client} store={store}>
<App />
</ApolloProvider>
);
So, i decided to change the las part of the code to this, and it actually worked
<ApolloProvider client={client}>
<Provider store={store}>
<App />
</Provider>
</ApolloProvider>
But if you go to settings, you'll see that ApolloProvider's child is the provider
So, could that cause a problem? is that the best way to connect redux and apollo/client ?
If you can help me to connect redux and apollo/client so i can use them normally, you're the greatest !
Thanks for your time ! .
You don't really "connect them together". You use both of them. And it works. But they don't have any real interaction as they don't know of each other - and they really don't need to have any interaction either.
What you are doing there, nesting different providers, is totally fine and is done in most apps. But as I said, that does not "connect" them in any way ;)
What is the best pattern for a large multi-component ReactJS app to integrate with a socket io back-end server?
Here are some of the requirements
The React application must connect to the backend (a server using a Flask-based socket.io implementation) upon login. The connection must be torn down on logout
The connection should be managed from a central place (as in I don't want every component to connect/disconnect to socket-io). This should also be a place to manage life-cycle of the socketio connection (disconnect, reconnect, etc).
Back-end will send async updates (a.k.a statistics for various components). These stats must be handled by the common socketio handling instance and pushed into redux store. The message body will have enough information to demux the messages.
The components themselves, should (preferably) not know about socket-io, they operate on the redux state.
Components can dispatch actions, that could potentially result in sending out a socketio message (to back-end).
[I don't have a use-case where a client needs to talk to another client.]
Few questions:
What is the right way to design this? At what point should I connect to socket-io?
I have a basic-layout component which is used by all pages. Is this the right place to hook up socket-io call? However, I see that this component is unloaded/loaded for each page. Somehow, this doesn't feel like the right place
I have seen some examples where every page opens a socketio connection. I am not sure if this is the right model?
I think you should probably store your socket on a Context, so that you can create your socket on your index.js file, like I did here :
import React from "react";
import App from "./App";
import socketIOClient from "socket.io-client";
import { MainProvider } from "./context/MainContext.js";
const ENDPOINT = "http://127.0.0.1:1234"; //Your backend endpoint
ReactDOM.render(
<React.StrictMode>
<MainProvider value={{socket: socketIOClient(ENDPOINT)}}>
<App />
</MainProvider>
</React.StrictMode>,
document.getElementById("root")
);
Then as it is on the context, you can access it in any component, like that :
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import MainContext from "./context/MainContext"; //import your context here
const myComponent = props => {
const myContext = useContext(MainContext); //your context is stored in a prop
return (
<div></div>
);
};
myComponent.propTypes = {
};
export default myComponent;
Finally you can access your socket in the component by calling myContext.socket
I want to keep a single instance of a third party api manager class in my react app.
I'm trying to achieve this using using the React Context Api like this:
Api Context:
import * as React from "react";
import { ApiManager } from "../ApiManager";
const defaultValue = new ApiManager()
const ApiContext = React.createContext(defaultValue);
const ApiProvider = ApiContext.Provider;
const ApiConsumer = ApiContext.Consumer;
const withApi = (enhanced) => {
return (
<ApiConsumer>
{api => enhanced }
</ApiConsumer>
)
}
export default ApiContext;
export {ApiContext, ApiProvider, ApiConsumer, withApi};
in my client I would do something like this:
const api = new ApiManager({
host: apiHost,
baseUrl: apiBaseUrl,
key: apKey,
sessionToken: persistedSessionToken
});
ReactDOM.hydrate(
<Provider store={store}>
<PersistGate loading={<h1>loading...</h1>} persistor={persistor}>
<BrowserRouter>
<ApiProvider value={api}>
<Main />
</ApiProvider>>
</BrowserRouter>
</PersistGate>
</Provider>, document.querySelector('#app')
);
I have 3 questions:
Does this even make sense?
How would I set the sessionToken if it gets renewed by the user?
How do I rehydrate the api instance after a page reload using redux-persist?
If you just want to use one instance of ApiManager then I don't think you need Context API. Just create an instance and export/import it in files where you need it.
You can wrap that third party api manager to add some methods you need like setSessionToken to set/update sessionToken when app loads or when user receives/refreshes it.
Why bother with redux-presist in this case (even if you decide to use Context API) if Redux is not involved. If you want to store sessionToken so store it in localStorage or any other storage you want, it has simple API to set/retrieve values, you don't need to use a library for it.
OS: Windows 10 Pro
apollo-boost: "^0.1.16"
apollo-client: "^2.4.2"
Does anyone know how to access the client.mutate method from Apollo now? I wish to do the following:
client.mutate({
mutation: REMOVE_FROM_CART_MUTATION,
variables: {
cartItem.id,
},
})
.catch(this.handleSubmitError);
....
withApollo(CartItem);
If you're using React, you can import withApollo like so:
import { withApollo } from 'react-apollo';
then make sure to wrap the component (I do this on export):
export default withApollo(CartItem);
By doing so, ApolloProvider will automatically inject the client to your props and you can access it from within the component by doing this.props.client.mutate(...); or this.props.client.query(...);
NOTE: this means your component must be a child of the ApolloProvider in your component tree. The Apollo docs recommend doing this at the highest level possible in your App, such as:
<ApolloProvider client={client}>
<App />
</ApolloProvider>
You can find more information on using the query and mutate APIs in the Apollo API client reference.
If you're trying to interact directly with your local cache, you can find information on the client.readyQuery() and client.writeQuery() APIs in the Apollo client GitHub repo.
I'm pretty new to rxjs, and trying to understand what's needed here to expose the Chat object in the Bot Framework, as I need to call some methods in it I'll add. I essentially need access to the created Chat component from the webpage, which right now has a BotChat.App. There's also a BotChat.Chat, but that doesn't seem to be the instance I need access to.
The following is used from the Bot Framework by calling BotChat.App({params});
That in turn creates a Chat component (eventually in App.tsx below). I need to basically expose the Chat instance that is used, as I want to modify it.
BotChat.ts (Complete)
export { App, AppProps } from './App';
export { Chat, ChatProps } from './Chat';
export * from 'botframework-directlinejs';
export { queryParams } from './Attachment';
export { SpeechOptions } from './SpeechOptions'
export { Speech } from './SpeechModule'
import { FormatOptions } from './Types';
// below are shims for compatibility with old browsers (IE 10 being the main culprit)
import 'core-js/modules/es6.string.starts-with';
import 'core-js/modules/es6.array.find';
import 'core-js/modules/es6.array.find-index';
And here in App.tsx note the Chat component used below. That is what I need to expose up through the webpage. A bit confused as to if it's exporting a "Chat" type as opposed to getting access to the instance of Chat being used in App.tsx. Hope this makes some sense :)
App.tsx (Complete)
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Chat, ChatProps } from './Chat';
import * as konsole from './Konsole';
export type AppProps = ChatProps;
export const App = (props: AppProps, container: HTMLElement) => {
konsole.log("BotChat.App props", props);
ReactDOM.render(React.createElement(AppContainer, props), container);
}
const AppContainer = (props: AppProps) =>
<div className="wc-app">
<Chat { ...props } /> //<--------------This is what I want to get
//access to on the webpage, which currently
//only uses BotChat.App() to initialize the
//web chat control. Not sure how to expose
//this _instance_ to App.tsx and then expose
//that instance to the webpage.
</div>;
Web Chat has a Redux store and a RxJS stream that you can expose to interact with the <Chat> component. In React, you can, but people usually don't expose any functions out of it. Short reason: the contract of a React component is props, not functions.
For RxJS stream that you can access the chat history, you can look at the backchannel sample. But it's a read-only stream.
For other interactivities, look at Store.ts to see what actions it is using. Then, expose the Redux store at Chat.ts (easy hack: thru window variable, better: make a callback props at <Chat>).
If you need more interactivities that is not in the existing Redux actions, feel free to add some more. For example, this pull request should give you a sense of injecting chat history.