Confusion how HOC are used in React - reactjs

I was learning React and came across something called higher order component and also found this code:
function withSubscription(WrappedComponent, selectData) {
// ...and returns another component...
return class extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
data: selectData(DataSource, props)
};
}
componentDidMount() {
// ... that takes care of the subscription...
DataSource.addChangeListener(this.handleChange);
}
componentWillUnmount() {
DataSource.removeChangeListener(this.handleChange);
}
handleChange() {
this.setState({
data: selectData(DataSource, this.props)
});
}
render() {
// ... and renders the wrapped component with the fresh data!
// Notice that we pass through any additional props
return <WrappedComponent data={this.state.data} {...this.props} />;
}
};
}
Well, basically it is clear what HOC does it accepts a component and returns enhanced version of that accepted component. But what confuses me is that how the component can be returned since we do not call render method, that is, we just need to do this withSubscription(someComponent) and enhanced someComponent will be returned but we do not call render method which actually returns that enhanced component.How is that possible?

You are actually confusing HOC with a React Component.
The name is misleading.
HOC is not a concept unqiue to React. This is a concept that is derived from the world of functional programming.
In functional programming we have Higher Order Functions (HOF)
A HOF is a function that takes another function as a parameter.
Consider the following example:
function greaterThan(n) {
return m => m > n;
}
let greaterThan10 = greaterThan(10);
console.log(greaterThan10(11));
// β†’ true
greaterThan is higher order function, it accepts a function as a parameter.
.map,.filter in JS are too HOF. They take function as a parameter.
Similarily we have HOCs.
Formal definition of HOC
A higher-order component is a function that takes a component and
returns a new component.
Did you notice it?It is not a component. It is a function that takes a component as a parameter. It also returns a component.
Consider the following example:
const hocWrapper = (PassedComponent) =>
({ children, ...props }) =>
<PassedComponent {...props}>
{children.split("").reverse().join("")}
</PassedComponent>
const name = (props) => <span>{props.children}</span>
const reversedName = hocWrapper(name)
<reversedName>Hello</reversedName>
In the above example we have
HOC - hocWrapper
PassedComponent - React Component
Return value - React Component [with enhanced functionality]
hocWrapper is a simple function which takes PassedComponent as a parameter and returns an enhanced version of PassedComponent.

Related

const in class react i18n [duplicate]

In this example, I have this react class:
class MyDiv extends React.component
constructor(){
this.state={sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
The question is if I can add React hooks to this. I understand that React-Hooks is alternative to React Class style. But if I wish to slowly migrate into React hooks, can I add useful hooks into Classes?
High order components are how we have been doing this type of thing until hooks came along. You can write a simple high order component wrapper for your hook.
function withMyHook(Component) {
return function WrappedComponent(props) {
const myHookValue = useMyHook();
return <Component {...props} myHookValue={myHookValue} />;
}
}
While this isn't truly using a hook directly from a class component, this will at least allow you to use the logic of your hook from a class component, without refactoring.
class MyComponent extends React.Component {
render(){
const myHookValue = this.props.myHookValue;
return <div>{myHookValue}</div>;
}
}
export default withMyHook(MyComponent);
Class components don't support hooks -
According to the Hooks-FAQ:
You can’t use Hooks inside of a class component, but you can definitely mix classes and function components with Hooks in a single tree. Whether a component is a class or a function that uses Hooks is an implementation detail of that component. In the longer term, we expect Hooks to be the primary way people write React components.
As other answers already explain, hooks API was designed to provide function components with functionality that currently is available only in class components. Hooks aren't supposed to used in class components.
Class components can be written to make easier a migration to function components.
With a single state:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { state } = this;
const setState = state => this.setState(state);
return <div onClick={() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
}
is converted to
const MyDiv = () => {
const [state, setState] = useState({sampleState: 'hello world'});
return <div onClick={() => setState({sampleState: 1})}>{state.sampleState}</div>;
}
Notice that useState state setter doesn't merge state properties automatically, this should be covered with setState(prevState => ({ ...prevState, foo: 1 }));
With multiple states:
class MyDiv extends Component {
state = {sampleState: 'hello world'};
render(){
const { sampleState } = this.state;
const setSampleState = sampleState => this.setState({ sampleState });
return <div onClick={() => setSampleState(1)}>{sampleState}</div>;
}
}
is converted to
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div onClick={() => setSampleState(1)}>{sampleState}</div>;
}
Complementing Joel Cox's good answer
Render Props also enable the usage of Hooks inside class components, if more flexibility is needed:
class MyDiv extends React.Component {
render() {
return (
<HookWrapper
// pass state/props from inside of MyDiv to Hook
someProp={42}
// process Hook return value
render={hookValue => <div>Hello World! {hookValue}</div>}
/>
);
}
}
function HookWrapper({ someProp, render }) {
const hookValue = useCustomHook(someProp);
return render(hookValue);
}
For side effect Hooks without return value:
function HookWrapper({ someProp }) {
useCustomHook(someProp);
return null;
}
// ... usage
<HookWrapper someProp={42} />
Source: React Training
you can achieve this by generic High order components
HOC
import React from 'react';
const withHook = (Component, useHook, hookName = 'hookvalue') => {
return function WrappedComponent(props) {
const hookValue = useHook();
return <Component {...props} {...{[hookName]: hookValue}} />;
};
};
export default withHook;
Usage
class MyComponent extends React.Component {
render(){
const myUseHookValue = this.props.myUseHookValue;
return <div>{myUseHookValue}</div>;
}
}
export default withHook(MyComponent, useHook, 'myUseHookValue');
Hooks are not meant to be used for classes but rather functions. If you wish to use hooks, you can start by writing new code as functional components with hooks
According to React FAQs
You can’t use Hooks inside of a class component, but you can
definitely mix classes and function components with Hooks in a single
tree. Whether a component is a class or a function that uses Hooks is
an implementation detail of that component. In the longer term, we
expect Hooks to be the primary way people write React components.
const MyDiv = () => {
const [sampleState, setState] = useState('hello world');
render(){
return <div>{sampleState}</div>
}
}
You can use the react-universal-hooks library. It lets you use the "useXXX" functions within the render function of class-components.
It's worked great for me so far. The only issue is that since it doesn't use the official hooks, the values don't show react-devtools.
To get around this, I created an equivalent by wrapping the hooks, and having them store their data (using object-mutation to prevent re-renders) on component.state.hookValues. (you can access the component by auto-wrapping the component render functions, to run set currentCompBeingRendered = this)
For more info on this issue (and details on the workaround), see here: https://github.com/salvoravida/react-universal-hooks/issues/7
Stateful components or containers or class-based components ever support the functions of React Hooks, so we don't need to React Hooks in Stateful components just in stateless components.
Some additional informations
What are React Hooks?
So what are hooks? Well hooks are a new way or offer us a new way of writing our components.
Thus far, of course we have functional and class-based components, right? Functional components receive props and you return some JSX code that should be rendered to the screen.
They are great for presentation, so for rendering the UI part, not so much about the business logic and they are typically focused on one or a few purposes per component.
Class-based components on the other hand also will receive props but they also have this internal state. Therefore class-based components are the components which actually hold the majority of our business logic, so with business logic, I mean things like we make an HTTP request and we need to handle the response and to change the internal state of the app or maybe even without HTTP. A user fills out the form and we want to show this somewhere on the screen, we need state for this, we need class-based components for this and therefore we also typically use class based components to orchestrate our other components and pass our state down as props to functional components for example.
Now one problem we have with this separation, with all the benefits it adds but one problem we have is that converting from one component form to the other is annoying. It's not really difficult but it is annoying.
If you ever found yourself in a situation where you needed to convert a functional component into a class-based one, it's a lot of typing and a lot of typing of always the same things, so it's annoying.
A bigger problem in quotation marks is that lifecycle hooks can be hard to use right.
Obviously, it's not hard to add componentDidMount and execute some code in there but knowing which lifecycle hook to use, when and how to use it correctly, that can be challenging especially in more complex applications and anyways, wouldn't it be nice if we had one way of creating components and that super component could then handle both state and side effects like HTTP requests and also render the user interface?
Well, this is exactly what hooks are all about. Hooks give us a new way of creating functional components and that is important.
React Hooks let you use react features and lifecycle without writing a class.
It's like the equivalent version of the class component with much smaller and readable form factor. You should migrate to React hooks because it's fun to write it.
But you can't write react hooks inside a class component, as it's introduced for functional component.
This can be easily converted to :
class MyDiv extends React.component
constructor(){
this.state={sampleState:'hello world'}
}
render(){
return <div>{this.state.sampleState}
}
}
const MyDiv = () => {
const [sampleState, setSampleState] = useState('hello world');
return <div>{sampleState}</div>
}
It won't be possible with your existing class components. You'll have to convert your class component into a functional component and then do something on the lines of -
function MyDiv() {
const [sampleState, setSampleState] = useState('hello world');
return (
<div>{sampleState}</div>
)
}
For me React.createRef() was helpful.
ex.:
constructor(props) {
super(props);
this.myRef = React.createRef();
}
...
<FunctionComponent ref={this.myRef} />
Origin post here.
I've made a library for this. React Hookable Component.
Usage is very simple. Replace extends Component or extends PureComponent with extends HookableComponent or extends HookablePureComponent. You can then use hooks in the render() method.
import { HookableComponent } from 'react-hookable-component';
// πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡
class ComponentThatUsesHook extends HookableComponent<Props, State> {
render() {
// πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡πŸ‘‡
const value = useSomeHook();
return <span>The value is {value}</span>;
}
}
if you didn't need to change your class component then create another functional component and do hook stuff and import it to class component
Doesn't work anymore in modern React Versions. Took me forever, but finally resulted going back to go ol' callbacks. Only thing that worked for me, all other's threw the know React Hook Call (outside functional component) error.
Non-React or React Context:
class WhateverClass {
private xyzHook: (XyzHookContextI) | undefined
public setHookAccessor (xyzHook: XyzHookContextI): void {
this.xyzHook = xyzHook
}
executeHook (): void {
const hookResult = this.xyzHook?.specificHookFunction()
...
}
}
export const Whatever = new WhateverClass() // singleton
Your hook (or your wrapper for an external Hook)
export interface XyzHookContextI {
specificHookFunction: () => Promise<string>
}
const XyzHookContext = createContext<XyzHookContextI>(undefined as any)
export function useXyzHook (): XyzHookContextI {
return useContext(XyzHookContextI)
}
export function XyzHook (props: PropsWithChildren<{}>): JSX.Element | null {
async function specificHookFunction (): Promise<void> {
...
}
const context: XyzHookContextI = {
specificHookFunction
}
// and here comes the magic in wiring that hook up with the non function component context via callback
Whatever.setHookAccessor(context)
return (
< XyzHookContext.Provider value={context}>
{props.children}
</XyzHookContext.Provider>
)
}
Voila, now you can use ANY react code (via hook) from any other context (class components, vanilla-js, …)!
(…hope I didn't make to many name change mistakes :P)
Yes, but not directly.
Try react-iifc, more details in its readme.
https://github.com/EnixCoda/react-iifc
Try with-component-hooks:
https://github.com/bplok20010/with-component-hooks
import withComponentHooks from 'with-component-hooks';
class MyComponent extends React.Component {
render(){
const props = this.props;
const [counter, set] = React.useState(0);
//TODO...
}
}
export default withComponentHooks(MyComponent)
2.Try react-iifc: https://github.com/EnixCoda/react-iifc

React implicit mapping mechanism

I am going through the tutorial:
https://www.robinwieruch.de/gentle-introduction-higher-order-components/
And they have such kind of statements:
const withTodosNull = (Component) => (props) =>
!props.todos
? null
: <Component { ...props } />
As I understand Component is passed to the function, then its props get implicitly taken and fed into the return function. I do not understand how the React is doing that. I would honestly expect something like (Component) => (Component.props). What is the mechanism for this? Is it mapped correctly only if we supply the argument as props or we can supply any name? Is there a specific name for such implicit assignment?
Update
Maybe I was not clear enough, but what I am really interested in is from where props appear in the inner function if they are not passed to the previous, outer, function. I understand how the HOCs work, how to think about them, but this moment is very unclear and what in React is doing that? Is there some kind of an engine running behind the scenes, idk...
This technique is called higher-order components (HOCs) and is a way of extending components with some extra functionality.
It might look easier at first if you rewrite it using regular functions instead of arrow functions:
function withTodosNull(Component) {
return function(props) {
if (!props.todos) {
return null;
} else {
return <Component {...props} />
}
}
}
withTodosNull takes in a component and returns a new component. If this new component that is returned gets a todos prop, the component passed into the HOC will be rendered with all the props. If todos is not given as a prop, null will be rendered.
It will be probably easier to understand if we rewrite arrow functions using classic function():
function withTodosNull(Component) {
return function(props) {
if (!props.todos) {
return null;
}
return <Component {...props} />;
}
}
The inner unnamed function is a functional component. It takes properties and renders either as null or as Component.
The outer function is something called high-order-component (HoC). It is a function, that wraps a component and returns a new component.
There is no connection between Component and props. They are only parameters of two different functions.
Specifically, when you call:
class MyComponent: React.Component {
}
const myComponentWithTodosNull = withTodosNull(MyComponent);
it is the same as writing:
const myComponentWithTodosNull = props => {
if (!props.todos) {
return null;
}
return <MyComponent {...props} />;
}
Higher-Order Components are functions that "enhance" components passed as a parameter. To understand where the props are coming from let's see what would it look like to use such component.
There's our basic component, which will be passed to the HoC:
function TodoList(props) {
return (
<div>We have {props.todos.length} tasks to do!</div>
);
}
And now, we can use our HoC to create new "enhanced" component, which prevents displaying this message, when there aren't any tasks left:
const EnhancedTodoList = withTodosNull(TodoList);
Then we can use this new component, to render the message (or not, if there aren't any tasks):
<EnhancedTodoList todos={someTodos} />
As you can see, EnhancedTodoList is the first component, which gets todos. Then it decides if props should be passed to TodoList, or should it return null, when there aren't any todos.
Todos are passed explicitly from the component which renders the HoC. EnhancedTodoList acts just like a filter for TodoList.

How to pass component props to react-navigation's static navigationOptions function

I have a react component class that declares a custom react-navigation header via the static navigationOptions function which react-navigation then calls automatically. The problem is, I want to render the header conditionally based on props passed to the component rather than simply props passed in as parameters to the route. I can't simply set them on componentDidMount, since the props I'm referencing change after the component it mounted and I need those to trickle into the header.
I figured out a way to do it and thought I'd post it here.
First, a helper method. The purpose of this is just to make sure we don't enter into an infinite loop when we pass the props to navigation.params inside componentDidUpdate--and to encapsulate smidge of logic involved in actually mapping the prop. This uses JSON.stringify to compare the props. Depending on what you're doing, you may need to substitute that bit with a more sophisticated comparison.
export function mapPropsToNavigationRouteParams(
props,
prevProps,
getPropsToMap,
) {
if (!props) return;
const propsToMap = getPropsToMap(props);
if (
!prevProps ||
JSON.stringify(getPropsToMap(prevProps)) !== JSON.stringify(propsToMap)
) {
props.navigation.setParams(getPropsToMap(props));
}
}
Then, in the component with the method above pulled in we can do something like this...
const getPropsToMapToNavigation = props => ({
myComponentProp: props.myComponentProp,
});
class MyComponent extends React.Component {
componentDidMount() {
mapPropsToNavigationRouteParams(
this.props,
null,
getPropsToMapToNavigation,
);
}
componentDidUpdate(prevProps) {
mapPropsToNavigationRouteParams(
this.props,
prevProps,
getPropsToMapToNavigation,
);
}
static navigationOptions = ({navigation}) => {
const {params} = navigation.state;
const myComponentProp = params ? params.myComponentProp : null;
// ...
}
Given the limitations of react-router, this is the best I could come up with. If you have a better solution, let me know!

ReactJs - Access Wrapped State from HOC Wrapper

Im trying to use HOC pattern instead of Object Oriented to avoid redundant code.
The situation is simple as explained below:
In HomePage I have something like this:
const WrappedComponent = Wrapper(Wrapped);
<WrappedComponent { ...this.props } />
In the Wrapper "component", I want to expose a method called foo_method that is an Ajax Call to a WebServer. The result must be written in the state of Wrapped Component.
Now, WrappedComponent can call foo_method but when inside Wrapper, I have no scope of Wrapped state and this.props contains the props of HomePage, not wrapper so I cant create a callback function in Wrapper to be called.
Am I forgetting something in the implementation of HOC?
I think your HOC should look something like this, every WrappedComponent will get result (null while loading and API response after) in the props also wrapped component can call exposed fetch function manually via props.fetchFunction().
function Wrapper(WrappedComponent) {
const fetchData = () => {
return fetch('something');
};
return class extend React.Component {
constructor(props) {
super(props);
this.state = {
result: null,
};
}
componentDidMount() {
fetchData().then((result) => {
this.setState({result});
});
}
render() {
return (
<WrappedComponent
result={this.state.result}
fetchFunction={fetchData}
{...this.props}
/>
);
}
}
}

React / Redux Components not re-rendering on state change

I think this question has been answer several time but I can't find my specific case.
https://codesandbox.io/s/jjy9l3003
So basically I have an App component that trigger an action that change a state call "isSmall" to true if the screen is resized and less than 500px (and false if it is higher)
class App extends React.Component {
...
resizeHandeler(e) {
const { window, dispatch } = this.props;
if (window.innerWidth < 500 && !this.state.isSmall) {
dispatch(isSmallAction(true));
this.setState({ isSmall: true });
} else if (window.innerWidth >= 500 && this.state.isSmall) {
dispatch(isSmallAction(false));
console.log(isSmallAction(false));
this.setState({ isSmall: false })
}
};
componentDidMount() {
const { window } = this.props;
window.addEventListener('resize', this.resizeHandeler.bind(this));
}
...
I have an other component called HeaderContainer who is a child of App and connected to the Store and the state "isSmall", I want this component to rerender when the "isSmall" change state... but it is not
class Header extends React.Component {
constructor(props) {
super(props);
this.isSmall = props.isSmall;
this.isHome = props.isHome;
}
...
render() {
return (
<div>
{
this.isSmall
?
(<div>Is small</div>)
:
(<div>is BIG</div>)
}
</div>
);
}
...
even if I can see through the console that redux is actually updating the store the Header component is not re-rendering.
Can someone point out what I am missing ?
Am I misunderstanding the "connect()" redux-react function ?
Looking at your code on the link you posted your component is connected to the redux store via connect
const mapStateToProps = (state, ownProps) => {
return {
isHome: ownProps.isHome,
isSmall: state.get('isSmall')
}
}
export const HeaderContainer = connect(mapStateToProps)(Header);
That means that the props you are accessing in your mapStateToProps function (isHome and isSmall) are taken from the redux store and passed as props into your components.
To have React re-render your component you have to use 'this.props' inside the render function (as render is called every time a prop change):
render() {
return (
<div>
{
this.props.isSmall
?
(<div>Is small</div>)
:
(<div>is BIG</div>)
}
</div>
);
}
You are doing it well in the constructor but the constructor is only called once before the component is mounted. You should have a look at react lifecycle methods: https://reactjs.org/docs/react-component.html#constructor
You could remove entirely the constructor in your Header.js file.
You should also avoid using public class properties (e.g. this.isSmall = props.isSmall; ) in react when possible and make use of the React local state when your component needs it: https://reactjs.org/docs/state-and-lifecycle.html#adding-local-state-to-a-class
A component is only mounted once and then only being updated by getting passed new props. You constructor is therefore only being called once before mount. That means that the instance properties you set there will never change during the lifetime of your mounted component. You have to directly Access this.props in your render() function to make updating work. You can remove the constructor as he doesn't do anything useful in this case.

Resources