React HOC can't resolve import - reactjs

Hi I am creating my first HOC in react and I have hit a snag. I import a Contentservice inside the class HOC and I have a simple Page class that is wrapped by the WithBackend.
When i navigate to the page component using react Route i get the get the error:
TypeError: Cannot read property 'getPage' of undefined
When i debug the code, i can see the service is available in the constructor but when it gets to the getPage method, i get the alert(id) but then it breaks on the line
this.service.getPage(id);
This is the wrapper function:
import React from "react";
import ContentService from "./ContentService";
const WithBackend = (WrappedComponent) => {
class HOC extends React.Component {
constructor() {
super();
this.service = new ContentService();
}
getPage(id) {
alert(id);
this.service.getPage(id);
}
render() {
return <WrappedComponent getPage={this.getPage} {...this.props} />;
}
}
return HOC;
};
export default WithBackend;
This is the component that is wrapped:
import React, { Component } from "react";
import WithBackend from "./WithBackend";
class PageX extends Component {
render() {
return (
<div>
<h2>Home</h2>
</div>
);
}
componentDidMount() {
this.props.getPage("123");
}
}
const Page = WithBackend(PageX);
export default Page;
This is the ContentService class:
class ContentService {
getPage(id) {
alert(id);
return "Some page";
}
}
export default ContentService;
Can anyone see what i am doing wrong please? Also I am only changing the name of my page to PageX so i can import if after it is being wrapped by the name Page. Is this necessary? I rather just keep the whole thing named page.
I would appreciate your help with this.

Add the following to your code
const WithBackend = (WrappedComponent) => {
class HOC extends React.Component {
constructor() {
super();
this.service = new ContentService();
this.getPage = this.getPage.bind(this) // <-- Add this
}
getPage(id) {
alert(id);
this.service.getPage(id);
}
render() {
return <WrappedComponent getPage={this.getPage} {...this.props} />;
}
}
return HOC;
};
I would also encourage you to read about how this binding works in javascript.
Here is a link to a blog that I liked.

You need to bind this instance to getPage, the recommended way is using arrow function:
getPage = (id) => {
alert(id);
this.service.getPage(id);
}
// Or in constructor
this.getPage = this.getPage.bind(this);
// Or in the event itself
onClick={this.getPage.bind(this)}

Related

Getting data as a Class Component rather than a Hook

I'm using Auth0, and can grab the data using hooks like so:
const { user } = useAuth0()
How can I refactor and get that same data in a Class Component? I just cannot figure it out or find a good example. I've tried:
this.state = { user: useAuth0()}
But no luck...
auth0-react provides a HOC withAuth0 which you can use with class components as mentioned here
import React, { Component } from 'react';
import { withAuth0 } from '#auth0/auth0-react';
class Profile extends Component {
render() {
// `this.props.auth0` has all the same properties as the `useAuth0` hook
const { user } = this.props.auth0;
return <div>Hello {user.name}</div>;
}
}
export default withAuth0(Profile);
Wrapper function component outside class component;
const AuthWrapper = (E)=> {
const WrapperComponent = (props)=> {
const { user } = useAuth0()
return <E user={user} {...props} />
}
return WrapperComponent;
}
Class Component
#AuthWrapper
class AuthDemo extends Component {
render() {
const { user } = this.props;
...
}
}
you need to use higher order component to implements.
more details: use-with-a-class-component

React JS - Pass Provider components methods to this.children

In React can methods be passed to {this.children} in a container consumer model. What I mean to ask is I have a provider component and I need to pass or refer the provider components methods in the child component.
export default class ContainerCompo extends React.Component {
constructor(props) {
super(props);
this.myHocComponent = null;
}
methodOne() {
//some code
}
methodTwo() {
//some code
}
render() {
return (
{this.props.children}
}
}
export default class InputComponent extends React.Component {
constructor(props) {
super(props);
this.myHocComponent = null;
}
validate() {
ContainerCompo.methodOne(param)
}
render() {
return <InputComponent />
}
// Rendering the components
<ContainerCompo>
<InputComponent containerMethods={methods of ContainerCompo}/>
</ContainerCompo>
I hope my question is clear here, please suggest
First create a react context.
import React, { Component, createContext } from 'react';
// Create's authentication context to be use anywhere in the app
const ContainerContext = createContext();
export default ContainerContext;
Then create a provider for it.
export default class ContainerProvider extends Component {
constructor(props) {
super(props);
this.myHocComponent = null;
}
methodOne() {
//some code
}
methodTwo() {
//some code
}
render() {
const { children } = this.props;
return (
<ContainerContext.Provider
value={{
container: {
methodOne: (...params) => this.methodOne(...params),
methodTwo: (...params) => this.methodTwo(...params)
}
}}
>
{children}
</ContainerContext.Provider>
)}}
Wrap your App with the provider.
import ContainerProvider from './ContainerProvider'
<ContainerProvider>
<App />
</ContainerProvider>
Then create a consumer for the context
export default function withContainer(InComponent) {
return function ContainerComponent(props) {
return (
<ContainerContext.Consumer>
{({ container }) => <InComponent {...props} container={container} />}
</ContainerContext.Consumer>
);
};
}
Then import the consumer and user in your components and you will get the methods as props
import withContainer from './ContainerConsumer'
render() {
const { container } = this.props;
return(<div />)
}
export default withContainer(YourComponent);

Do I have to use a constructor when importing an external module I made in React?

I made a module in react.
So, I imported the module. And then, the function of the external module was called using the constructor.
import { connect } from './api';
...
class App extends Component {
constructor(props) {
super(props);
connect(message => {
console.log(message);
});
}
render(){
...
}
}
But I would like to express class fields syntax without using a constructor.
import { connect } from './api';
...
class App extends Component {
connect(message => {
console.log(message);
});
render(){
...
}
}
The results of the above code, 'connect' function is not executed because 'connect' is not declared.
Can't I get an function of external module without a constructor?
Here is your connect.js:
export const connect = message => {
console.log(message);
};
Here is your component:
import React from 'react';
import { connect } from './connect';
class App extends React.Component {
componentDidMount() {
connect('connected');
}
render() {
return (
<div>
<h1>Some Text...</h1>
</div>
);
}
}
export default App;
Should be fairly clear... If you have a question ask...

React TS: Despite passing method through wrapper, child still can't access getPage()

I'm trying to build a fetch method that can be shared to a bunch of Reader components through a higher order component. I believe I've built the HOC right, but I'm not 100% sure.
import React, { Component } from 'react';
import base from "./firebase";
export default (ChildComponent) => {
class GetPage extends Component<{},any> {
constructor(props: any) {
super(props);
this.state = {
text: "Hii"
};
}
public getPage(page: string) {
base
.fetch(page, { context: this, })
.then(data => this.setState({ text: data }));
console.log(this.state.text)
}
public render() {
return <ChildComponent getPage={this.getPage} text={...this.state.text} {...this.props}/>;
}
}
return GetPage;
};
You can see that I'm importing the HOC on the second line , but despite this, the 'Reader' component is throwing an error that 'getPage' is no where to be found.
import * as React from "react";
import GetPage from "./fetch";
class Reader extends React.Component<{},any>{
public componentWillMount() {
this.getPage('1A1');
}
public render() {
return <div{...getPage('1A1')}>{...this.state.text}</div>;
}
}
export default (GetPage(Reader));
Inside your Reader component instead of accessing this.getpage try with this.props.getpage
and I don't understand why you are doing with following:
<div{...getPage('1A1')}>

Passing a component into React setState value

I've got a Meteor app using React. I've added Session variables and want to pass the new Session value (which will be another React component) into another react component.
The user will click the p-tag in the SideNav and reset the Session to a React component.
SideNav component:
import React from 'react';
import { Session } from 'meteor/session';
import SonataContent from './sonata-content';
export default () => {
injectSonataText = () => {
const sonataContent = <SonataContent/>;
Session.set('MainContent', sonataContent); /* Set Session value to component */
};
return (
<div className="side-nav">
<h2>Explore</h2>
<p onClick={this.injectSonataText.bind(this)}><i className="material-icons">child_care</i><span> Sonatas</span></p>
</div>
)
}
In the MainWindow, Tracker.autorun re-runs and sets the state to the component and renders the new state value.
Main Window component:
import React from 'react';
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';
export default class MainWindow extends React.Component {
constructor(props) {
super(props);
this.state = {
text: ""
}
}
componentDidMount() {
this.mainWindowTracker = Tracker.autorun(() => {
const text = Session.get('MainContent');
this.setState({text: text});
});
}
componentWillUnmount() {
this.mainWindowTracker.stop();
}
render() {
return (
<p>{this.state.text}</p>
)
}
}
I'm getting an error "Invariant Violation: Objects are not valid as a React child". Is this caused by the component being used in setState? Is there a way to do this?
Session set function accepts as a value EJSON-able Object which I think may not work with React Object.
However I would try (only a guess though):
injectSonataText = () => {
Session.set('MainContent', SonataContent); /* Set Session value to component */
};
...
export default class MainWindow extends React.Component {
constructor(props) {
super(props);
this.state = {
Component: null,
}
}
componentDidMount() {
this.mainWindowTracker = Tracker.autorun(() => {
const MainContent = Session.get('MainContent');
this.setState({Component: MainContent});
});
}
componentWillUnmount() {
this.mainWindowTracker.stop();
}
render() {
const { Component } = this.state;
return (
<p>
{
Component && <Component />
}
</p>
)
}
}

Resources