How to apply a HOC dynamically - reactjs

I'm trying to apply the HOC to every child in my custom component. But I can't solve how to implement this for dynamic wrapped component type. Let say we have:
function myHOC<P>(WrappedComponent: React.ComponentType<P>):React.ComponentType<P> {
return class extends React.Component<P> {
...
render() {
return <WrappedComponent />;
}
const MyHOC = myHOC(???); //It won't do!
class MyComponent extends React.Component<Props, State> {
...
render() {
const items = this.props.children.map((child) => {
<MyHOC /> //I want to use it something like this!
});
return (
<div>
{items}
</div>
);
}
}
What do I need to add?

You can't apply HOC dynamically. If you want to use shared stateful logic dynamically you can think about render props pattern.

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

How to limit queryselector to a react component

I have a react component with a list of child-components. In the child-component I want to target a specific DOM element e.g., to change the color in its ComponentDidMount method. How would I do this?
Parent component
export class ListComponent extends Component<...> {
render(): ReactNode {
return (
<div>
<ListItemComponent key="123"/>
<ListItemComponent key="456"/>
<ListItemComponent key="789"/>
</div>
);
}
}
Child component
export class ListComponent extends Component<...> {
componentDidMount(): void {
// const elementToChange = document.queryselector(".toTarget"); // Only works for the first element as it only targets the first on the page
const elementToChange = THISREACTCOMPONENT.queryselector(".toTarget");
elementToChange.style.backgroundColor = "123123";
}
render(): ReactNode {
return (
<div>
<div className="toTarget">
</div>
);
}
}
So, the question is, what should be instead of THISREACTCOMPONENT? How to target an element exclusively within the react component?
use a react ref.
Refs were created so you won't have to use queryselector, as interacting directly with the dom may lead to react bugs further down the line.
export class ListComponent extends Component<...> { {
constructor(props) {
super(props);
this.myRef = React.createRef(); // Get a reference to a DOM element
}
componentDidMount(): void {
const elementToChange = this.myref.current;
elementToChange.style.backgroundColor = "123123";
}
render() {
return (
<div>
<div className="toTarget" ref={this.myRef}> // binds this element to the this.myref variable
</div>
)
}
}
You could use Document.querySelectorAll to get all matching elements
document.querySelectorAll returns an array of matching element.
Then you would do it like so:
componentDidMount(): void {
const elements = document.querySelectorAll(".toTarget");
elements.forEach((el) => {
el.style.backgroundColor = "123123";
});
}

React Components - No Inheritance, how can pass ref or use HOC for my BaseComponent

I'm building a Web components library where I have a series of components which ideally inherit / takes advantage of BaseComponent. After some reading, inheritance isn't recommended in React and instead I could use forwardRef? or probably higher-order components? The only thing, I'm not very familiar with this concept and couldn't find good examples, tutorial specific for my case. Hopefully someone can tell me how to approach this, what's best-practice?
One of technique I have in mind for the BaseComponent is leveraging IntersectionObserver to trigger animations. As you can imagine, I don't want to put this logic in multiple places. For the sick of having a basic example, below I simply have a click event listener on the BaseComponent:
class Image extends React.Component {
render() {
return (
<div>
<div>
<img className={className} src={src} alt={alt} />
</div>
</div>
);
}
}
export default Image;
// export default withMagic(Image); ??
class BaseComponent extends React.Component {
withMagic() {
}
componentDidMount() {
{/* ref should be <img> DOM element */}
ref.addEventListener("click", this.handleClick);
}
}
export BaseComponent();
Thanks
HoC probably the better solution
// 2. WrappedComponent
export default WrappedComponent => {
// If u want to deal with class
class NewComponent extends React.Component {
//3
handleClick = () => {
// Your Events
}
render () {
//4
return <WrappedComponent {...this.props} handleClick={this.handleClick} />
}
}
// If u want to deal with functional Component
const NewComponent = props => {
const handleClick = () => // your events
return <WrappedComponent {...props} handleClick={handleClick} />
}
return NewComponent
}
How to use ?
import withClick from 'path/withClick'
const A = props => {
return (
//4
<button onClick={props.handleClick}>Click here</button>
)
}
// 1.
export default withClick(A)
How this magic work ?
U are using withClick method by passing A component as a params
A component is named as WrappedComponent inside withClick function
inside the withClick function, u create a new component with your desired handler, logic or even state, then pass them as a props into WrappedComponent
after that, ur current component will have these handler or logic
If u want to pass params, u can use Higher order Function that returns Higher Order Component like
export default (params1, params2, ...paramsn) => WrappedComponent => {
// remain like the same
}

React - prevent HOC from recomputing based on props

I'm wondering if there's a pattern that allows me to prevent an HOC from recalculating based on some condition, here's an example:
const DumbComponent = () => <button>Click me<button/>;
// Third party HOC, that I can't modify
const SmartComponent = Component => class extends Component {
componentWillReceiveProps() {
// Complex stuff that only depends on one or 2 props
this.state.math = doExpensiveMath(props);
}
render() {
return <Component {...this.props} math={this.state.math} />;
}
}
const FinalComponent = SmartComponent(DumbComponent);
What I'm looking for, is a pattern that prevents this HOC from doing its thing if the props I know it depends on haven't changed. But that doesn't stop the entire tree from rerendering based on props like shouldComponentUpdate would do.
The catch is, that this HOC comes from another library and ideally I don't want to fork it.
What i got is you want to prevent hoc to recompute certain logic for that you can do as below :-
const DumbComponent = () => <button>Click me<button/>;
// Third party HOC
const SmartComponent = Component => class extends Component {
componentWillReceiveProps() {
// Complex stuff that only depends on one or 2 props
this.state.math = doExpensiveMath(props);
}
render() {
return <Component {...this.props} math={this.state.math} />;
}
}
const withHoc = SmartComponent(DumbComponent);
class FinalComponent extends Component {
render() {
if (your condition here) {
return (
<withHoc {...this.props} />
);
}
else {
return <DumbComponent {...this.props}/>;
}
}
}
export default FinalComponent;

Pass event through nested components bottom to top

While this question has been asked before I did not find an answer. I have components nested to the level of great grandchild and I don't know how to get the data from the bottom to the top.
<Parent/>
<Child/>
<GrandChild/>
<GreatGrandChild/>
See an example: fiddle
The great grandchild is a form and I want the input data to get to the parent at the top. I had it working when it was just nested one level deep, but now that it is deeply nested it does not work. I'm not sure how to even pass the event up two levels.
I've heard using redux is possible but I wonder if there is a way to avoid it. Or, how do I avoid the nesting? Even through they are all actually separate components should I just move them into one big component? This might work but seems like bad practice?
Very simplified, you could just pass the function through all the components:
class GreatGrandChild extends React.Component {
render() {
return (
<div>
<input onChange={this.props.onChange}/>
<h2>I'm the GreatGrandChild</h2>
</div>
)
}
}
class GrandChild extends React.Component {
render() {
return (
<div>
<h2>I'm the GrandChild</h2>
<GreatGrandChild onChange={this.props.onChange}/>
</div>
)
}
}
class Child extends React.Component {
render() {
return (
<div>
<GrandChild onChange={this.props.onChange}/>
<h2>I'm the child</h2>
</div>
)
}
}
class Top extends React.Component {
constructor(props) {
super(props)
this.state = {
}
}
handleChildchange = (e) => {
console.log('child event on parent')
console.log(e.target.value);
}
render() {
return (
<div>
<Child onChange={this.handleChildchange}/>
<h2>I'm the parent</h2>
</div>
)
}
}
ReactDOM.render(<Top />, document.querySelector("#app"))
Redux is overkill for simple passing of props. You can pass props down through each child but it's easier to use the Context API like so:
Parent Component:
const MyContext = React.createContext('default');
export MyContext;
class Parent extends React.Component {
myFunction() {
//Do something here
}
render() {
return (
<MyContext.Provider value={this.myFunction}>
<ChildComponent />
</MyContext.Provider>
);
}
}
export default Parent;
Child Component:
import { MyContext } from './Parent';
class ChildComponent extends React.Component {
render() {
const { myFunction } = this.context;
return (
<div onClick={myFunction}>Click Me!</div>
);
}
}
ChildComponent.contextType = MyContext;
You can use the context as deep as you'd like, as long as you import it.
Simply pass a callback down from the parent via the props and make Sure it's passed all the way down to where you need it.
You also can pass props to your each child component in nesting and whenever values changed, you can call a parent function (nested) to get latest values in parent.

Resources