How to query graphql endpint from a class based react component - javascript

The Load product is maybe we call it hook whose purpose of the life is fetch the data from a graphql backend
Here its how LOAD_PRODUCT LOOKS LIKE
import { gql } from '#apollo/client'
export const LOAD_PRODUCTS = gql`
query{
categories {
name
products {
id,
name,
inStock,
gallery,
category
}
}
}
`
import React, { Component } from 'react'
import { useQuery,gql } from '#apollo/client'
import { LOAD_PRODUCTS } from '../../graphql/productAction'
export class ProductListing extends Component {
constructor(){
super();
const {error,loading,data} = useQuery()
}
render() {
return (
<div>ProductListing</div>
)
}
}
export default ProductListing
for now i just want to fire the load user hook and save set the data to the different state there must be a method to do this i search on google but nothing help i just cant use fetch method to get the result

You can also query a graphql endpoint using the Query component or the HOC. But note that since class based components are considered legacy those do not receive any updates anymore.
Using the Query component:
import { Query } from '#apollo/client/react/components';
export class ProductListing extends Component {
render() {
return (
<Query query={LOAD_PRODUCTS}>
{({data}) => <div>Render data here ...</div>}
</Query>
)
}
}
Using the HOC:
import { graphql } from '#apollo/client/react/hoc';
class ProductListing extends Component {
render() {
const data = this.props.data;
return <div>Render data here ...</div>;
}
}
export default graphql(LOAD_PRODUCTS)(ProductListing);

Related

Get data fro firestore with React Native

I need to get data from Firestore but i can't, i need to know if my code is ok, because it doesn't work or something else is missing.
This is my firestore services
fireservices.js
import React from 'react';
import * as firebase from 'firebase';
import { firebaseConfig } from '../firebase_const';
import 'firebase/firestore';
firebase.initializeApp(firebaseConfig)
class FireServices{
static async getLocalization(idOfert) {
firebase.firestore.collection('users').doc(idOfert)
}
}
export default FireServices;
And this is my class, this class use the method to get data
SecondClass.js
import React from 'react';
import FireServices from '../services/fireservices';
export default class SecondClass extends React.Component {
componentDidMount = async () => {
this.onStart()
}
onStart = () => {
FireServices.getLocalization('email#hotmail.com').get().then(doc => {
console.log(doc)
})
}
render(){
return (
<View>
</View>
)
}
You are not returning from getLocalization.
It should be
static async getLocalization(idOfert) {
return firebase.firestore.collection('users').doc(idOfert)
}

Pass graphQL mutation function as prop or inject it into child component?

I'm using react-apollo in my reactJS/graphQL-Application.
Sometimes I do need the same mutation for multiple components. So what is the best way to use mutations and updating the data after calling the mutations?
Should I inject the mutation in the top component and pass it down to all children (example 2) or should I inject the mutation everywhere it is needed (example 1)?
With example 1 it is easier to update the existing data after the mutation call, while passing the doMutation()-function of parent component makes the updating mor complicating for me.
Example 1 (multiple injection)
Parent
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import Child from './Child'
import { MUTATION } from 'graphql/'
export class Parent extends Component {
doMutation (event, { name, value }) {
const { someMutation } = this.props
return someMutation({
variables: {
value
}
})
}
render () {
const { data } = this.props
return (
<>
<Button onClick='this.doMutation.bind(this')>Click me to manipulate data</Button>
<Child data={data} />
</>
)
}
}
export default graphql(MUTATION, { name: 'someMutation' })(Parent)
Cild
import React, { Component } from 'react'
import GrandChild from './GrandChild'
export default class Child extends Component {
render () {
return <GrandChild data={this.props.data} />
}
}
GrandCild
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import { MUTATION } from 'graphql/'
export class GrandChild extends Component {
doMutation (event, { name, value }) {
const { someMutation } = this.props
return someMutation({
variables: {
value
}
})
}
render () {
const { data } = this.props
return (
<Button onClick='this.doMutation.bind(this')>Click me to manipulate data</Button>
)
}
}
export default graphql(MUTATION, { name: 'someMutation' })(GrandChild)
Example 2 (passing function as prop)
Parent
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import Child from './Child'
import { MUTATION } from 'graphql/'
export class Parent extends Component {
doMutation (event, { name, value }) {
const { someMutation } = this.props
return someMutation({
variables: {
value
}
})
}
render () {
const { data } = this.props
return (
<>
<Button onClick='this.doMutation.bind(this')>Click me to manipulate data</Button>
<Child doMutation={this.doMutation.bind(this)} data={data} />
</>
)
}
}
export default graphql(MUTATION, { name: 'someMutation' })(Parent)
Cild
import React, { Component } from 'react'
import GrandChild from './GrandChild'
export default class Child extends Component {
render () {
return <GrandChild doMutation={this.props.doMutation} data={this.props.data} />
}
}
GrandCild
import React, { Component } from 'react'
import { graphql } from 'react-apollo'
import { Button } from 'semantic-ui-react'
import { MUTATION } from 'graphql/'
export default class GrandChild extends Component {
render () {
const { doMutation } = this.props
return (
<Button onClick='doMutation.bind(this')>Click me to manipulate data</Button>
)
}
}
This mostly comes down to preference, but there are some advantages to avoiding passing down the query results as props, namely:
Better performance. Avoiding a top-down prop flow means fewer unnecessary re-renders of middle components.
Simpler data flow. No need to trace where the props are coming.
More flexibility. Even if two components need the same data initially, requirements change over time. Having each component use their own hook means you can change the parameters passed to the hook for one component without affecting the other.
Less coupling between the parent and child components. You can refactor the parent or add the child component to other parts of your app without worrying about having to ensure the data is passed down to the child component.

this.props.match.params passed into child component after authorisation

I have recently started building a big project on React using also a Firebase with authentication and I cannot quite understand the relation between the react-router-dom links and React components.
I am struggling with getting the
this.props.match.params // which is going to be 2018 / 2019 / 2020... etc
in the component, which renders as a dynamic route (like unique post component).
I have tried to use only a simple class component and this works but the problem is, without the authentication everyone can access this admin route and everyone would be allowed to edit and delete data there. I want it to be accessed only by authenticated users. (Admins)
So this is how my piece of code looks like:
Main component: (where the link is)
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
class SeasonBox extends Component {
render() {
return (
<Link className='seasonbox' to={`/adminseason/${this.props.season}`}>
<p className='seasonbox__season'>{this.props.season}/{this.props.season+1}</p>
</Link>
)
}
}
export default SeasonBox;
And the component that renders after the link is clicked:
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { compose } from 'recompose'
import { withAuthorisation } from '../Session'
import { withFirebase } from '../Firebase'
const AdminMatchesBox = ({authUser}) => (
<div>{authUser ? <AdminMatchesBoxAuth /> : <AdminMatchesBoxNonAuth />} </div>
)
class AdminMatchesBoxAuth extends Component {
render() {
return (
<div>
Hey I am the season {this.props.match.params}!
<Link to={'/adminmatches'}>Wróć</Link>
</div>
)
}
}
const AdminMatchesBoxNonAuth = () => (
<div>
<h1>You do not have permission to visit this page.</h1>
</div>
)
const mapStateToProps = state => ({
authUser: state.sessionState.authUser
});
const condition = authUser => !!authUser
export default compose(withAuthorisation(condition), connect(mapStateToProps),withFirebase)(AdminMatchesBox);
So if I don't use authorisation, and I use only a single class component I can get this.props.match.params -> which is the id of the website and I need it to access data from the database.
However, I want it to not be visible by not logged users and I had to process it through the authorisation process.
I am receiving an error
Cannot read property 'params' of undefined.
I have no clue how to pass match.params into the AdminMatchesBoxAuth component.
Could anyone advice?
By wrapping withRouter you able to access params
Try this
import { withRouter } from "react-router";
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { connect } from 'react-redux'
import { compose } from 'recompose'
import { withAuthorisation } from '../Session'
import { withFirebase } from '../Firebase'
const AdminMatchesBox = ({authUser}) => (
<div>{authUser ? <AdminMatchesBoxAuth /> : <AdminMatchesBoxNonAuth />} </div>
)
class AdminMatchesBoxAuth extends Component {
constructor (props){
super(props)
}
render() {
return (
<div>
Hey I am the season {this.props.match.params}!
<Link to={'/adminmatches'}>Wróć</Link>
</div>
)
}
}
const AdminMatchesBoxNonAuth = () => (
<div>
<h1>You do not have permission to visit this page.</h1>
</div>
)
const mapStateToProps = state => ({
authUser: state.sessionState.authUser
});
const condition = authUser => !!authUser
export default compose(withRouter, withAuthorisation(condition), connect(mapStateToProps),withFirebase)(AdminMatchesBox)

Export pure functional component without decorators

I'm trying to export a component without the decorators (connect() in this case)
for unit testing with jest.
So, how could I do this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
export class Header extends Component {
render(){
return <pre>Header</pre>
}
}
export default connect()(Header);
With this component (the export at the beginning doesn't work, it stills exports the connected component)
export let Header = props => {
render(){
return <pre>Header</pre>
}
}
Header = connect()(Header);
export default Header;
Use different variable for your connected component as the following code:
export let Header = props => {
render(){
return <pre>Header</pre>
}
}
let HeaderConnected = connect()(Header);
export default HeaderConnected;
Now you can import your Header freely without using connect()
This can be done without even changing default export:
export let Header = props => {
render(){
return <pre>Header</pre>
}
}
export default connect()(Header);
There may be no need to export original component for connect alone because most well-designed HOCs expose original component:
import Header from '...';
const OriginalHeader = Header.WrappedComponent;

react-redux nested component not ReactClass in parent?

I am a bit new to react and redux, but made quite a lot of progress.
I am using redux connect to map state to props. Was working like charm, until I got this situation:
Parent component is using mapStateToProps, and here is the source code for it:
import React from 'react';
import { connect } from 'react-redux'
import { NestedComponent } from './NestedComponent'
class ParentElement extends React.Component {
render() {
return (
<div className="App">
<NestedComponent/>
</div>
);
}
}
const mapStateToProps = state => {
const { questions } = state
return {
questions
}
}
ParentElement.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default connect(mapStateToProps)(ParentElement)
Here is the code for the nested element:
import React from 'react';
import { connect } from 'react-redux'
class NestedComponent extends React.Component {
render() {
return (
<div> I am nested</div>
);
}
};
const mapStateToProps = state => {
const { questions } = state
return {
questions
}
}
NestedComponent.contextTypes = {
router: React.PropTypes.object.isRequired
}
export default connect(mapStateToProps)(NestedComponent)
When I try to show the parent element, I get this error:
Warning: React.createElement: type should not be null, undefined,
boolean, or number. It should be a string (for DOM elements) or a
ReactClass (for composite components). Check the render method of
ParentElement.
What am I missing / doing wrong?
Import header file like this:-
import NestedComponent from './NestedComponent'
Without braces.
When a class is exported as a default then it is imported without braces because there is only one default class in a file but, when the class is exported without default you have to import it with braces because there can be more than one class with export keywords in a file (es6 conventions).

Categories