get props from children component through hoc - reactjs

I have a component which is going through an hoc, but i want to get some props of this component inside the hoc. All works fine but i can not find out how to get the props out of this child component into the hoc.
here is the component which is going through the hoc, and that is this 'getAction' props i want to extract in the hoc
class ProjectPage2 extends Component {
render() {
return (
<Project2 getAction="getAction"/>
);
};
};
export default PageHandler(ProjectPage2)
here is the hoc component (imported as PageHandler in the ProjectPage2)
export default (ChildComponent) => {
class ComposedComponent extends Component {
render() {
// here i want to get the 'getAction' props, which is inside this ChildComponent
// because i need to use it into this hoc logic
return <ChildComponent {...this.props} />;
}
}
const mapStateToProps = (state) => {
return {
comments: state.project2
}
};
const loadData = (store) => {
return store.dispatch(getProject2());
};
return {
loadData,
component: connect(mapStateToProps, { getProject2 })(ComposedComponent)
}
};
if some one have an idea it would be great. Thanks.

I think you're very close already. It looks to me like you want the final result to be something like:
<Project2 getAction="getAction" comments={...} />
But what ends up getting rendered is just:
<Project2 getAction="getAction" />
See, the custom props of your HOC are passed to your child component via the child's props. You aren't using those, so the child just completely ignores the HOC. You can fix this with:
class ProjectPage2 extends Component {
render() {
return (
<Project2 getAction="getAction" {...this.props} />
);
};
}

Thank you for the answer. But it s not what i was looking for. I wanted to get into the HOC some children component's props passing through. But i finally get the idea which solved it. In fact it s so simple......
i wanted to pass the "getAction" string into the HOC. But i didn t find any solution to extract it (from the passing through component) there.
The solution is simply to pass it into the export default
class ProjectPage2 extends Component {
render() {
return (
// i was trying to use the component props
// <Project2 getAction="getAction"/>
// but no need
<Project2 />
);
};
};
// pass it into the fonction fix it
export default PageHandler(ProjectPage2, "getAction")
then get it in the HOC
export default (ChildComponent, varAction) => {
class ComposedComponent extends Component {
console.log(varAction) // return getAction

Related

Is it possible to render inside a functional component in reactjs?

I want to know the proper method to use render(){} while I'm using the functional component.
i'm new on reactjs, so far i'm always using functional component on everything :
const Something = () => {
}
export default Something
What i want is to render object which is react-scroll-parallax, while i'm using functional component, but i don't know the proper method to do that :
const Something = () => {
render() {
return (
<ParallaxProvider>
<Parallax className="custom-class" y={[-20, 20]} tagOuter="figure">
<ImageBg src="../../images/wpbatik.jpg" />
</Parallax>
</ParallaxProvider>
);
}
}
export default Something
Thank you
In a functional component, you use return and it will work the same way as return inside of the render() {} function in a class-based component.
Example:
function App() {
return(
<div>Some stuff inside</div>
)
}
Here's a class based version of it:
class App extends React.Component {
render() {
return <div>Some stuff inside</div>;
}
}

React HOC wrapper

I am not sure if I am doing this right but I want to make a hoc that will display components based on if the user is admin. This is my HOC:
export const WithUser = (Component) => (props) => {
if (props.admin) {
return <Component {...props} />;
}
return null;
};
There is an error when I use it Functions are not valid as a React child. It doesnt make sense to me.
I want to use it like this:
<WithUser admin>
<button>Hi</button>
</WithUser>
But I get that error. Maybe Im not using HOCs correctly. I just want to wrap components that the user need to be an admin to view
you can take a look HOC document from react official website
modify your code to this:
// admin prop should be obtained from within WithUser or other places such as redux store or react context
export const WithUser = (Component) => (props) => {
if (props.admin) {
return <Button {...props} />;
}
return null;
};
class Button extends React.Component {
render() {
return <button>Hi</button>
}
}
export default WithUser(Button)
WithUser is not a component. It is a function that takes a component and returns a modified component. That's what a Higher-Order-Component (HOC) is.
You can write a component that does what you want with your desired syntax:
<WithUser admin>
<button>Hi</button>
</WithUser>
But it won't be an HOC. Instead you want to use the children prop to access the child JSX elements and conditionally render them.
export const WithUser = ({admin, children}) => {
return admin ? <>{children}</> : null;
};

React - What is meant by 'Do not use HOC’s in the render method of a component. Access the HOC outside the component definition.'?

I am learning HOCs and keep reading the above quote, but I do not understand what it means. If my HOC adds a method to my consuming component, can I use that method in the render method like so? If not how would I do what I am trying to do here:
import React, { Component } from 'react';
import { withMyHOC } from '../with_my_component'
class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
const { methodFromHOC }= this.props;
const result = methodFromHOC(someArgument);
return (
<div >
{result}
</div>
)
}
}
export default withMyHOC(MyComponent );
When you say, do not use HOC within the render method, it means that you shouldn't create an instance of the component wrapped by HOC within the render method of another component. For example, if you have a App Component which uses MyComponent, it shouldn't be like below
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
const { methodFromHOC }= this.props;
const result = methodFromHOC(someArgument);
return (
<div >
{result}
</div>
)
}
}
export default MyComponent;
import { withMyHOC } from '../with_my_component'
export default class App extends React.Component {
render() {
const Wrap = withMyHOC(MyComponent);
return (
<div>
{/* Other Code */}
<Wrap />
</div>
)
}
}
Why you shouldn't use it like above is because everytime render method is called a new instance of the MyComponent is created wrapped by HOC called Wrap and hence everytime it be be mounted again instead of going by the natural lifecycle or React.
However if your HOC passes a function as props, you can use it within the render as long as it doens't cause a re-render again otherwise it will lead to a infinite loop.
Also its better to memoize functions which are called in render directly to avoid computation again and again
CodeSandbox Demo
A High Order Component is a function which returns a Component, not jsx. When wrapping a component with an hoc, you're not changing the returned value of your component, you're changing the signature itself. Consider the following hoc
const withFoo = Component => props =>{
return <Component {...props} foo='foo' />
}
withFoo is a function which takes a Component (not jsx) as argument and returns a component. You don't need to call an hoc from render because the values it injects are already inside props of the wrapped component.
An hoc tells how a wrapped component will look like, changes it's definition so the only place to use it is in the component definition itself. Calling an hoc inside render creates a new instance of that component on each render. It's the equivalent of
const Component = () =>{
const ChildComponent = () =>{
return <span> Child </span>
}
return <ChildComponent /> //You're declaring again on each render
}
Use your high order components like this
const Component = ({ foo }) => <div>{ foo }</div>
export default withFoo(Component)
Or
const Component = withFoo(({ foo }) => <div>{ foo }</div>)

Possible to forward a ref using React.Suspense and React.Lazy?

I wondering if it would be possible to use React 16's lazy, Suspense, createRef and forwardRef features together in order to attach a reference to a dynamically imported component. Does anyone know if this is possible. I tried to follow the example (https://github.com/facebook/react/pull/13446/commits/4295ad8e216e0747a22eac3eed73c66b153270d4#diff-e7eafbb41b012aba463f5a2f8fc00f65R1614), however it doesn't quite seem to work with dynamically imported components.
I have been able to get similar desired behavior by setting custom props in the parent component, passing it down to the child component and then setting the ref to that prop in the child's render function(Example below). My only issue with this approach is that it may not be the cleanest solution and it may be difficult to keep the implementation consistent across a large team. It will also make it easier when attempting to place the ref on the actual component.
// Working (Undesired implementation)
// Parent.js
const LazyClass = lazy(() => { return import('./Child') };
class Parent extends React.Component {
this.childRef = React.createRef();
render() {
return (
<Suspense fallback={<div>Loading</div>}>
<Child forwardRef={this.childRef} />
</Suspense>
);
}
}
// Child.js
class Child extends React.Component {
render() {
return (<div>I am the Child!</div>);
}
}
export default React.forwardRef(({forwardRef, ...props}/*, ref*/) =>
<Child {...props} ref={forwardRef} />
);
//////////////////////////////////////////////////////
// Desired Implementation with React.forwardRef()
//Parent.js
const LazyClass = lazy(() => { return import('./Child') };
class Parent extends React.Component {
this.childRef = React.createRef();
render() {
return (
<Suspense fallback={<div>Loading</div>}>
<Child ref={this.childRef} />
</Suspense>
);
}
}
// Child.js
class Child extends React.Component {
render() {
return (<div>I am the child</div>);
}
}
export default React.forwardRef((props, ref) =>
<Child { ...props } ref={ref} />
);
Setting the ref directly on a Lazily loaded component always returns null. It would be nice if it returned the value from React.createRef().
The "ref as a props" approach is the smaller one but as you said you have to consider prop collision. The approach you linked is still correct. The test only changed slightly:
Update: Not sure if this was a bug previously but lazy now forwards refs automatically. Just be sure you export a component that can hold a ref.
See in action:
https://codesandbox.io/s/v8wmpvqnk0

How to use Higher Order function (or alternative) for wrapping a React component without the component continually unmounting?

I have a React component (Parent) within which there is another componet (Child) that is wrapped using a Higher Order function (HOWrapper). The problem I am having is that each time the Parent component renders, the Child component unmounts and then re-mounts. I need to find a way that prevents the Child component from unmounting, but still continue to wrap it in a component whose name is dynamically assigned. I also want the option to pass additional parameters to the HOWrapper function, that may also be dynamically generated in the render() function of Parent. Any ideas?
Parent component:
import { HOWrapper } from './somepath';
import Child from './someotherpath';
export default class Parent extends Component {
...
render(){
let ChildWrapper = HOWrapper(Child);
return (
<ChildWrapper {...this.props} />
);
}
}
Higher Order function:
export function HOWrapper(WrappedComponent) {
return class Blanket extends Component {
constructor(props) {
super(props);
this.state = {
...
};
}
...
render() {
return (
<WrappedComponent
{...this.props}
/>
);
}
}
}
Because an HOC returns a component, a more typical approach to using them is once when exporting them, not on every render call.
let YourComponent = props => <div />
export default HOC(YourComponent)
Then if you want to do anything dynamic pass new props to it.
render() { return <YourComponent dynamicProps={foo} /> }

Resources