ApolloProvider client - how to access from React Class component? - reactjs

I am building React App and need to use class components.
I have an ApolloClient set up in index.js and it is passing the client to the ApolloProvider. How do I access it in my App component (class component)? Is it even possible? I also have setup Redux and mapped state to props with connect (I thought about using export default withApollo(App) but then I lose state to props mapping with connect()).
Can someone help/explain how to correctly implement apollo-client with react class components? Should I create new ApolloClient in each class component?
index.js
const apolloClient = new ApolloClient({
uri: "http://localhost:4000/",
cache: new InMemoryCache(),
});
...
<ApolloProvider client={apolloClient}>
<App />
</ApolloProvider>
App.js
class App extends Component {
render() {
...
}
}
const mapStateToProps = (state) => {
return {
...
};
};
export default connect(mapStateToProps)(App);

To use ApolloClient in a class-based React component, you will need to make sure that your component is wrapped in an ApolloProvider component. You can use the ApolloConsumer component to get access to the ApolloClient instance.
import React from 'react';
import { ApolloConsumer } from '#apollo/client';
class MyComponent extends React.Component {
render() {
return (
<div>
<ApolloConsumer>
{client => (
<button onClick={() => client.writeData({ data: { isLoggedIn: true } })}>
Log in
</button>
)}
</ApolloConsumer>
</div>
);
}
}

Related

how can i use react redux in class component?

im a new to redux, and i want to know if it possible to use redux in class component.
we know that hooks works only in function component, so i export a function to use useSelector to access the store :
import { useSelector, useDispatch } from "react-redux";
export default function Selector() {
const counter = useSelector((state) => state.counter);
return counter;
}
and import it to the compone component so will be like this:
import React, { Component } from "react";
import selector from "../Store/selector";
export class Compone extends Component {
componentDidMount() {
console.log(selector());
}
render() {
return (
<>
<h1>
Counter: <span>0</span>
</h1>
<button style={{ marginRight: "10px" }}>Increase</button>
<button>Decrease</button>
</>
);
}
}
export default Compone;
and i import compone component to the App root component:
import React, { Component } from "react";
import Compone from "../components/compone/Compone";
export class App extends Component {
render() {
return (
<div>
<Compone />
</div>
);
}
}
export default App;
so this didn't work for me, is there a way to use redux in class component?,
how to use redux in class component,
how to use react redux in class component,
First of all you have to create some actions and some reducers.
Then you need to create a store using the reducers.
After that you can use connect method of react-redux with your class component.

How and where do I use the data from an Apollo Client?

How and where do I have to put that query so that I can map through it and display the categories in a header. I'm a noob and all the apollo documentation is made with hooks and functional components, but I have to do this assignment with class based components and I just can't figure it out.
index.js:
const client = new ApolloClient({
uri: "http://localhost:4000/graphql",
cache: new InMemoryCache(),
});
ReactDOM.render(
<ApolloProvider client={client}>
<App />
</ApolloProvider>,
document.getElementById("root")
);
App.js:
class App extends Component {
render() {
return (
<>
<Header />
</>
);
}
}
export default App;
Header.js:
class Header extends Component {
render() {
return (
<header>
<ul className="nav-list">
//Display categories here with map in a <li className="nav-item">
</ul>
</header>
)
}
}
query I need for header elements :
const QUERY = gql`
query getCategories {
categories {
name
}
}
`;
Hooks don't work with class components - but you can wrap your class components and pass the hook result as props to the class component:
import React from 'react';
import { useScreenWidth } from '../hooks/useScreenWidth';
export const withQueryHOC = (Component, query) => {
return (props) => {
const { loading, error, data } = useQuery(query);
return <Component loading={loading} error={error} data={data} {...props} />;
};
};
This is called a Higher-Order Component
Where Component is the class component you want to wrap. This way you can use class components but still have access to the hooks.
You should export you component like so:
export default withQueryHOC(YourComponentHere);
In your component you should access loading, error and data through this.props

Catch Data from URL params in react class Compoent

First of all I like to convey thanks all the wise programmer. After updating react react-router-dom i am facing this problem. Here i want to mention one thing that, i am a "class component" lover.
However, This is my base component in react.
import React, { Fragment, Component } from 'react'
import axios from 'axios'
import { Col , Row} from 'react-bootstrap'
import { Link } from 'react-router-dom'
export default class Blog extends Component {
constructor(props) {
super(props)
this.state = {
data:[]
}
}
componentDidMount()
{
axios.get("https://jsonplaceholder.typicode.com/posts")
.then((response)=>{
if(response.status===200)
{
this.setState({
data:response.data
})
}
})
.catch((error)=>{})
}
render() {
const allData = this.state.data;
const blogFull = allData.map((val)=>{
var title = val.title;
var body = val.body;
var id = val.id;
return(
<Col key={id} lg={4}>
<Link to={"/post/"+id}><h1>{title}</h1></Link>
<p>{body}</p>
</Col>
)
})
return (
<Fragment>
<Row>
{blogFull}
</Row>
</Fragment>
)
}
}
and this is my next component
import axios from 'axios'
import React, { Component, Fragment } from 'react'
import { useParams } from 'react-router'
export default class Post extends Component {
constructor(props) {
super(props)
this.state = {
mydata:[],
}
}
componentDidMount()
{
axios.get("https://jsonplaceholder.typicode.com/posts/")
.then((response)=>{
if(response.status===200)
{
this.setState({
mydata:response.data
})
}
})
.catch((error)=>{
})
}
render() {
const dataAll = this.state.mydata;
return (
<Fragment>
data retriving
<h1>{dataAll.title}</h1>
<p>{dataAll.body}</p>
</Fragment>
)
}
}
My Route is here :
<Routes>
<Route exact path="/" element={<Blog/>}/>
<Route exact path="/post/:id" element={<Post/>}/>
</Routes>
Can anyone tell me that how can i get data in post component from base component via its url parameter? The "match" object is not working in current update of react-router-dom. I want help for class component.
Issue
In react-router-dom v6 the Route components no longer have route props (history, location, and match), and the current solution is to use the React hooks "versions" of these to use within the components being rendered. React hooks can't be used in class components though.
To access the match params with a class component you must either convert to a function component, or roll your own custom withRouter Higher Order Component to inject the "route props" like the withRouter HOC from react-router-dom v5.x did.
Solution
I won't cover converting a class component to function component. Here's an example custom withRouter HOC:
const withRouter = WrappedComponent => props => {
const params = useParams();
// etc... other react-router-dom v6 hooks
return (
<WrappedComponent
{...props}
params={params}
// etc...
/>
);
};
And decorate the component with the new HOC.
export default withRouter(Post);
This will inject a params prop for the class component.
this.props.params.id

How to use refs with react-redux's connect HOC on two components?

I have two components which both use the connect HOC.
import {connect} from "react-redux";
import ComponentB from "./ComponentB";
class ComponentA extends Component {
render(){
return {
<div>
<button
onClick={this.refs.ComponentB.showAlert()}
>
Button
</button>
<ComponentB
ref={instance => {
this.ComponentB = instance.getWrappedInstance();
}}
/>
</div>
}
}
}
export default connect(mapStateToProps, {}, null, {withRef: true})(ComponentA)
Having ComponantA with the connect HOC gives me the error "TypeError: Cannot read property 'getWrappedInstance' of null"
export default ComponantA;
Not using the HOC would not give me this error.
import {connect} from "react-redux";
class ComponentB extends Component {
showAlert = () => {
alert("Please Work");
}
render(){
return {
<div>ComponentB</div>
}
}
}
export default connect(mapStateToProps, {}, null, {withRef: true})(ComponentB)
React.createRef was introduced in React 16.3 and is supposed to be used like:
this.componentBRef = React.createRef();
...
<button
onClick={() => this.componentBRef.current.getWrappedInstance().showAlert()}
>
Button
</button>
<ComponentB
ref={this.componentBRef};
}}
/>
As explained in this answer, the pattern used in createRef allows to lazily access a ref through current property because this.componentBRef.current is initially null.
Since Redux is in use, there's a chance that the interaction between components should be performed via Redux instead.

Next.js Redux integration Could not find "store" in either the context or props

I am currently trying to integrate my redux store to my Next.js react applcation. The only issue now is when I try to call connect inside my index.js file.
Maybe it has something to do with the way my app is laid out? I tried console.log(this.props) inside index.js but it doesn't seem to have anything sent down from provider.
Error:
Could not find "store" in either the context or props of "Connect(Page)". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(Page)".
page.js
import React from 'react';
import { Provider } from 'react-redux';
import store from '../store/store';
import Head from './head'
import Nav from './nav'
const childPage = (ChildPage) => {
return (
class Page extends React.Component {
render() {
return (
<Provider store={store}>
<div>
<Head />
<Nav />
<ChildPage />
</div>
</Provider>
)
}
}
)
}
export default childPage;
index.js
import React from 'react';
import { connect } from 'react-redux'
import Page from '../components/page';
export class Index extends React.Component {
render() {
return (
<div>
<div className="hero">
</div>
<style jsx>{`
`}</style>
</div>
)
}
}
export default connect(state => state)(Page(Index));
The structure order was incorrect.
export default connect(state=>state)(Page(Index));
This leads to connect() > Provider > Index
export default Page(connect(state=>state)(Index));
This leads to Provider > connect() > Index
So the answer is to do it like this:
export default Page(connect(state=>state)(Index));
You can use next-redux-wrapper npm package. Add withRouter hoc on _app.js page of your app.
Here is example: https://github.com/galishmann/nextjs-redux-example/blob/master/pages/_app.js

Resources