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 ;)
Related
If I'm already using next-auth within my next.js app can I add redux around it inside _app.js somehow?
what i tried is this:
import React from "react"
import { Provider } from 'next-auth/client'
import {Provider as ReduxProvider} from 'react-redux';
import {configureStore} from './store/configureStore';
import '../public/styles.css'
const store = configureStore();
export default function App ({ Component, pageProps }) {
return (
<ReduxProvider store={store}>
<Provider
// next-auth params, etc.
is this correct? does it work this way?
i'll also need to use redux-saga, new to the whole thing so i'm at a setup stage yet
The answer is YES. You can do that. I've tried myself and it works perfectly.
I have a react app that uses sessions with an express server using REST API.
In my Redux store(on the front end) I store "isLoggedIn" in the redux state. Based on that property I show either the login page , or the home page. Now when I open the website, the initial redux "isLoggedIn" state is false, so the question is, how do I check if the user is actually logged in. I am thinking about sending a request to the endpoint for fetching the data I need in the homepage, and if the user is not logged in, I would get an 401 response and then show the login page. Is this the correct approach?
Before I get into how you could persist your redux state I would advise(Note This is a personal view)
Going through the boiler plate code of setting that up is really unnecessarily long
Best way out for this is using express-session whereby the cookie is persisted for as long as you gave it e.g if you set cookie to be 3days it will stay for 3days
I so believe that it's industry standard working with httpOnly cookie for session handling as this is secure avoiding XSS attacks and CSRF attacks
Either way below is your solution to persisting Redux Store
So with persisting your redux state you can look into something like this
First run npm install redux-persist or yarn add redux-persist
Now time to create your redux store
So now when you create your redux store with createStore you want to pass your createStore function a persistReducer Once your store is created, pass it to the persistStore function, which will make sure that your redux state is persisted
Implementation below
import { createStore } from 'redux';
import { persistStore, persistReducer } from 'redux-persist';
import storage from 'redux-persist/lib/storage';
import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2';
import rootReducer from './reducers';
//Import above comes from a file **reducers** which has the combineReducers
// basically based on this code snippet
// I have my combineReducer object in another folder hope that it
//makes sense. Avoided to write it here to keep code short to show
//more of setup in store persisiting
const persistStoreConfigs = {
key: 'root',
storage: myAppStorage,
stateReconciler: autoMergeLevel2
};
const persistantReducer = persistReducer(persistStoreConfigs, rootReducer);
export const store = createStore(persistantReducer);
export const persistor = persistStore(store);
Now passing the store to the App level
import React from 'react';
import { Provider } from 'react-redux';
import { PersistGate } from 'redux-persist/lib/integration/react';
// This are coming from the store code above that we made
import { persistor, store } from './store';
// This are basically your Custom Componentd
import { HomePage, LoadingView } from './components';
const App = () => {
return (
<Provider store={store}>
// the loading and persistor props are both required!
// Noting that the LoadingView is a custom component
// But the persistor isn't
//The main aim of this two props is to delay the rendering of your app UI until the persited state is retrieved hence the loading screen component
<PersistGate loading={<LoadingView />} persistor={persistor}>
<HomePage />
</PersistGate>
</Provider>
);
};
export default App;
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.
I'm trying to upgrade to Redux V6 but am confused on how to use the createContext function and it's necessity. I know my store is created successfully, but when I try to run my app I get
Could not find "store" in the context of "Connect(ConfiguredApp)".
Either wrap the root component in a , or pass a custom React
context provider to and the corresponding React context
consumer to Connect(ConfiguredApp) in connect options.
Which tells me that my provider is not properly passing down the store for connect to grab. What am I doing wrong? Thanks!
import 'babel-polyfill';
import React from 'react';
import {render} from 'react-dom';
import {Provider} from 'react-redux';
import {ConnectedRouter} from 'connected-react-router';
import {history, store} from './store/store';
import Routes from './routes';
const customContext = React.createContext(null);
render(
<Provider store={store} context={customContext}>
<ConnectedRouter history={history} context={customContext}>
<Routes />
</ConnectedRouter>
</Provider>, document.getElementById('app'),
);
You almost definitely shouldn't be creating and passing in a custom context instance. That's only if, for some very specific reason, you want to use a context instance other than the default one that React-Redux already uses internally. (A hypothetical reason to do this would be if you are using one store for your whole app component tree, but there's a specific subtree that needs to receive data from a different store instead.)
If you actually wanted to use your own custom context instance, then you would need to pass the same context instance to both <Provider> and each connected component in the app that needs to receive data from that <Provider>.
Looking at the connected-react-router docs, they do claim that in CRR version 6, you can pass a context instance to <ConnectedRouter>, but that shouldn't be necessary here.
More specifically, if you look at the error message, it says the problem is in Connect(ConfiguredApp). So, it's your own connected component that is saying there's a context mismatch.
Ultimately, the answer here is to delete the context arguments from both <Provider> and <ConnectedRouter>. You don't need them.
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.