Getting data as a Class Component rather than a Hook - reactjs

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

Related

React Hoc function return class

Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
import './App.css';
import React, { Component } from 'react';
const OOO = () => {
//console.log(this.props.children)
return class extends Component {
render() {
return (
<Rem {...this.props} />
);
}
}
}
class Rem extends Component {
render() {
return (
<p>Helo</p>
)
}
}
export default OOO;
This may happen if you return a Component instead of <Component /> from render
That is exactly what you are doing here. Calling <OOO /> returns a class instead of a JSX element.
This isn't really a higher-order component because you are not taking the inner component Rem as an argument. Did you intend to? That would look something like this:
const withOOO = (InnerComponent) => {
return class extends Component {
render() {
return (
<InnerComponent {...this.props} />
);
}
}
}
class Rem extends Component { ... }
export default withOOO(Rem);
If this is just a component that uses Rem, not an HOC, then you don't need to create a new class.
const OOO = (props) => {
return <Rem {...props} />;
};
class Rem extends Component { ... }
export default OOO;
I think you used the function wrong, the function OOO returns a class and that class you can use. I have no idea why you would want to do this but here is how you can use the HOC:
//your code in a file called OOO.js
import React, { Component } from 'react';
const OOO = () => {
//you cannot log this.props here, it is not in the class
//console.log(this.props.children)
//I think you have to name the class but I'm not sure
//Have not used classes in React for quite some time
//even React documentation lists a large amount of
//disadvantages using classes and it's only around for
//legacy code
return class MyComponent extends Component {
render() {
//here you can log this.props
//console.log(this.props.children)
return <Rem {...this.props} />;
}
};
};
class Rem extends Component {
render() {
return <p>Helo</p>;
}
}
export default OOO;
//end of the OOO.js file
//here is how you can use it
import CreateComponent from 'OOO.js';
const Component = CreateComponent();
const MyComponent = ()=><Component />
export default MyComponent;

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);

React HOC can't resolve import

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)}

react context with componentdidupdate

I am running a pattern like so, the assumption is that SearchResultsContainer is mounted and somewhere a searchbar sets the input.
class SearchResults {
render() {
return(
<ResultsContext.Consumer value={input}>
{input => <SearchResultsContainer input=input}
</ResultsContext.Consumer>
)
}
class SearchResultsContainer
componentDidUpdate() {
//fetch data based on new input
if (check if data is the same) {
this.setState({
data: fetchedData
})
}
}
}
this will invoke a double fetch whenever a new context value has been called, because componentDidUpdate() will fire and set the data. On a new input from the results context, it will invoke componentDidUpdate(), fetch, set data, then invoke componentDidUpdate(), and fetch, then will check if data is the same and stop the loop.
Is this the right way to be using context?
The solution I used is to transfer the context to the props through a High Order Component.
I have used this very usefull github answer https://github.com/facebook/react/issues/12397#issuecomment-374004053
The result looks Like this :
my-context.js :
import React from "react";
export const MyContext = React.createContext({ foo: 'bar' });
export const withMyContext = Element => {
return React.forwardRef((props, ref) => {
return (
<MyContext.Consumer>
{context => <Element myContext={context} {...props} ref={ref} />}
</MyContext.Consumer>
);
});
};
An other component that consumes the context :
import { withMyContext } from "./path/to/my-context";
class MyComponent extends Component {
componentDidUpdate(prevProps) {
const {myContext} = this.props
if(myContext.foo !== prevProps.myContext.foo){
this.doSomething()
}
}
}
export default withMyContext(MyComponent);
There must be a context producer somewhere :
<MyContext.Provider value={{ foo: this.state.foo }}>
<MyComponent />
</MyContext.Provider>
Here is a way to do it that doesn't require passing the context through props from a parent.
// Context.js
import { createContext } from 'react'
export const Context = createContext({ example: 'context data' })
// This helps keep track of the previous context state
export class OldContext {
constructor(context) {
this.currentContext = context
this.value = {...context}
}
update() {
this.value = {...this.currentContext}
}
isOutdated() {
return JSON.stringify(this.value) !== JSON.stringify(this.currentContext)
}
}
// ContextProvider.js
import React, { Component } from 'react'
import { Context } from './Context.js'
import { MyComponent } from './MyComponent.js'
export class ContextProvider extends Component {
render(){
return (
<MyContext.provider>
{/* No need to pass context into props */}
<MyComponent />
</MyContext.provider>
)
}
}
// MyComponent.js
import React, { Component } from 'react'
import { Context, OldContext } from './Context.js'
export class MyComponent extends Component {
static contextType = Context
componentDidMount() {
this.oldContext = new OldContext(this.context)
}
componentDidUpdate() {
// Do all checks before updating the oldContext value
if (this.context.example !== this.oldContext.value.example) {
console.log('"example" in context has changed!')
}
// Update the oldContext value if the context values have changed
if (this.oldContext.isOutdated()) {
this.oldContext.update()
}
}
render(){
return <p>{this.props.context.example}</p>
}
}
You could pass just the value that is changing separately as a prop.
<MyContext.Provider value={{ foo: this.state.foo }}>
<MyComponent propToWatch={this.state.bar}/>
</MyContext.Provider>
The extent -> props wrapper seems to a recommended by the react staff. However, they dont seem to address if its an issue to wrap context in a prop for an then consume the context directly from the child of the child, etc.
If you have many of these props you are needing to watch, especially when not just at the ends of branches for the component tree, look at Redux, its more powerful that the built in React.extent.

How to avoid writing the same logic in components having a different layout?

How can I avoid writing the same code when two components share some same methods but have a different layout?
The sample components below have a method "renderLastItem" which uses prop "something" passed by the parent components.
I thought about using Higher Order Component Pattern but I'm not sure I I can pass props as an argument to Higher Order Component.
The sample code below is very simple, so in this sample code, I just need to use If statement and change the layout according to the type of components, but in real code, I have more codes and I want to avoid using if statement in order to change the layout according to the type of a component.
How can I avoid writing the same logic in multiple components?
ComponentA
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const propTypes = {};
const defaultProps = {};
class SampleA extends Component {
constructor(props) {
super(props);
}
renderLastItem() {
if(!this.props.something) {
return null;
}
return this.props.something[this.props.something.length - 1];
}
render() {
return (
<div>
<h1>Something</h1>
<p>{this.renderLastItem()}</p>
</div>
);
}
}
SampleA.propTypes = propTypes;
SampleA.defaultProps = defaultProps;
export default SampleA;
ComponentB
import React, { Component } from 'react';
import PropTypes from 'prop-types';
const propTypes = {};
const defaultProps = {};
class SampleB extends Component {
constructor(props) {
super(props);
}
renderLastItem() {
if(!this.props.something) {
return null;
}
return this.props.something[this.props.something.length - 1];
}
render() {
return (
<div>
<ul>
<li>Something</li>
<li>Something else</li>
<li>{this.renderLastItem()}</li>
</ul>
</div>
);
}
}
SampleB.propTypes = propTypes;
SampleB.defaultProps = defaultProps;
export default SampleB;
You absolutely can pass props to a Higher-Order Component! A HOC is simply a function that takes a Component as an argument and returns another Component as a result. So you could create a Higher-Order withLastOfSomething Component just like this:
function withLastOfSomething(Component) {
return function({something, ...otherProps}) {
const item = something ? something[something.length - 1] : null;
return <Component item={item} {...otherProps} />;
}
}
Or with ES6 arrow functions, even more compactly like this:
const withLastOfSomething = (Component) => ({something, ...otherProps}) => {
const item = something ? something[something.length - 1] : null;
return <Component item={item} {...otherProps} />;
}
And then use it like this:
const SampleBWithLastOfSomething = withLastOfSomething(SampleB);
return (<SampleBWithLastOfSomething something={...} />);
You can separate the function that takes the passed props and executes the logic,
export default renderLastItem = (passedProps) => {
if(!passedProps) {
return null;
}
return passedProps [passedProps.length - 1]
}
then import it wherever you need, like this:
import renderLastItem from './somewhere'
export default class SampleA extends Component {
render() {
return (
<div>
<h1>Something</h1>
<p>{renderLastItem(this.props.something)}</p>
</div>
)
}
}

Resources