Functional Component's props in Higher Order Component - reactjs

I am trying to understand passing the functional component's props to the returned functional component
**CODE ------------------------------------------------
App Component:
import React from 'react';
import ClickCounter from './ClickCounter';
const App = () => {
return (
<div className="App">
<ClickCounter firstName="John" lastName="Doe"/>
</div>
);
}
export default App;
ClickCounter Component:
import React from 'react'
import withCounter from './withCounter'
const ClickCounter = (props) => {
const { count, incrementCount, name } = props
return (
<div className="click-counter">
<button onClick={incrementCount}>Click Button</button>
<h2>{name}</h2>
<h1>{count}</h1>
</div>
)
}
export default withCounter(ClickCounter, 10)
withCounter Component (HOC)
import React, { useState } from 'react'
const withCounter = (WrappedComponent, incrementNumber) => {
return props => { // ** A **
console.log('props ---- ', props)
const [count, setCount] = useState(0)
return (
<WrappedComponent. // ** B **
count={count}
incrementCount={() => setCount(count + incrementNumber)}
{...props}
/>
)
}
}
export default withCounter
From my understanding, the withCounter return a functional component (A) that use useState Hook and and it return another component (B) which access the state through closure.
** QUESTION -------------------------------------------
My question is why the props in A is firstName="John" lastName="Doe", is it a React thing or Javascript's thing.
Does React pass the parameter's props (i.e wrapped component's props) to the returned functional component? or it is a Javascript's thing?
i read it in another post saying it is related to curry, but i cannot see it is related to curry, below is the post i read
HoC with React Hooks
const useSample = WrappedComponent => props => { // curry
const sampleCtx = useContext(SampleCtx);
return (
<WrappedComponent
{...props}
value={sampleCtx.value}
setValue={sampleCtx.setValue}
/>
);
};
Thank you!!

My question is why the props in A is firstName="John" lastName="Doe", is it a React thing or Javascript's thing.
This is because that's the props you passed to your Counter. Attributes on a component are props passed to functional components. This is a React thing.
<ClickCounter firstName="John" lastName="Doe"/>
When you put the component ClickCounter in your tree, it's actually just withCounter(ClickCounter, 10) being called, since that's your default export.
withCounter is a function that returns another function (curry) that takes props and returns a component. This is the setup for a functional component.
React runs this function and passes the props firstName="John" lastName="Doe" to that function. Then, those props are added to your WrappedComponent via the spread operator {...props}.

Related

Refactor use of this in React functional component?

I have this code in and example app and need to use it in a functional component:
ref={(c) => { this._carousel = c; }}
How can I assign the ref in an functional component?
You can use the React.useRef hook.
Example:
import React from "react";
function MyAwesomeFxnComponent() {
const ref = React.useRef(null);
return (
<Carousel ref={ref} />
);
}
With functional components you can use refs like this:
// Import react useRef hooks
import React, { useRef } from 'react';
export function CarouselWrapper {
// create your reference
const carouselRef = useRef(null);
return (
// Pass ref to your carousel component
<Carousel ref={carouselRef} />
)
};
Here you can read docs https://reactjs.org/docs/hooks-reference.html#useref

Map through two arrays of components and strings and render in one component

I have two arrays that I want to map through:
const social = ["Snapchat", "TikTok", "Dribbble", "Discord", "Facebook"];
const socialIcons = [<SnapchatIcon />, <DribbbleIcon />];
The socialIcons array are all components
How can I send both values as props into my DummyRectangle component? Here is my current code:
{social.map((s, index) => (
<div className="dummy_buttonsWrapper">
<DummRectangle social={s} socialIcons={i} />
</div>
))}
And here is DummyRectangle component:
function DummRectangle({ social, socialIcons }) {
// console.log("---->", socialIcons);
return (
<div>
<p>{social}</p>
{<socialIcon/>} // render social icon component
</div>
);
}
To do so, you don't need to wrap tags around your socialIcon in your DummRectangle. Also, it doesn't seem that you are passing the socialIcon component at all. If I were you, I would do something like this:
The following two are the components as an example that you would like to render (in your case - socialIcons)
// Comp1.js
import React from "react";
const Comp1 = () => <div>actual Comp1</div>;
export default Comp1;
// Comp2.js
import React from "react";
const Comp2 = () => <div>actual Comp2</div>;
export default Comp2;
Now, in your main Parent component, you would simply get the current component of the componentName (in your case - social) by accessing your component's array with an index. Then, you would pass this currentComponent as props to your Child component where you want to render it.
// App.js
import React from "react";
import Comp1 from "./Comp1";
import Comp2 from "./Comp2";
import DummyComponent from "./DummyComponent";
export default function App() {
const componentNames = ["Comp1", "Comp2"];
const components = [<Comp1 />, <Comp2 />];
return (
<div className="App">
{componentNames.map((name, index) => {
const currentComponent = components[index];
return (
<div>
<DummyComponent componentName={name} component={currentComponent} />
</div>
);
})}
</div>
);
}
In your Child component, you can simply render it by enclosing it into the brackets - no need to add tags. React will do all the rendering for you. In your case it would be { socialIcon }
// DummyComponent.js
import React from "react";
const DummyComponent = ({ componentName, component }) => {
return (
<div>
<p>{componentName}</p>
{component}
</div>
);
};
export default DummyComponent;
Link to Codesandbox with the above code for reference: click here

Get state variable from child component using React 16.8^ coding style

This question has already been asked but i cannot find an answer using hooks.
I need to read a state variable in the page that calls a component.
MyPage.js
import React from "react"
import MyComponent from "../components/MyComponent"
export default function MyPage() {
console.log("Read stateVariable value here " + stateVariable) // produce error
return (
<MyComponent />
)
}
MyComponent.js
import React, { useState } from "react"
import ExternalModule from "ExternalModule"
export default function MyComponent() {
const [stateVariable, setStateVariable] = useState(0))
return (
<div
onClick={setStateVariable(stateVariable + 1)}
>CLICK HERE
<ExternalModule
stateVariable={stateVariable}
/>
</div>
)
How to console.log stateVariable in MyPage?
When you have multiple components that need to access a piece of state, you want that state to be owned by the highest-up component in the tree and passed down to the rest.
Move the useState call up to MyPage and pass both stateVariable and setStateVariable down to MyComponent as props.
export default function MyPage() {
const [stateVariable, setStateVariable] = useState(0)
console.log("Read stateVariable value here " + stateVariable)
return (
<MyComponent
stateVariable={stateVariable}
setStateVariable={setStateVariable}
/>
)
}
export default function MyComponent({ stateVariable, setStateVariable]) {
return (
<div
onClick={setStateVariable(stateVariable + 1)}
>CLICK HERE
<ExternalModule
stateVariable={stateVariable}
/>
</div>
)
}

ReactJs: Prevent Rerender of wrapped component

I'm trying to prevent a re-render when using custom hook for hours now -.-, need some help ;O|
(Dont know if I should call this custom hook or functional hoc though)
I have a MessageList component that display a SimpleMessage wrapped in WithAvatarHeader.
Here is my profiler result:
Every time I add a message to the list, all messages are rendered again.
This isn't happening when I only use SimpleMessage in MessageList
Is there a way to memo(WithAvatarHeader) ?
MessageList :
import React from "react";
import SimpleMessage from "./SimpleMessage";
import WithAvatarHeader from "./WithAvatarHeader";
const MessageList = props => {
const Message = WithAvatarHeader(SimpleMessage);
return (
<div className="message-list">
{props.messages.map(message => {
return <Message message={message} key={message._id}/>;
})}
</div>
);
};
SimpleMessage:
import React, { memo } from "react";
const SimpleMessage = props => {
return (
<div className="simple-message">
{props.message}
</div>
);
};
export default memo(SimpleMessage);
WithAvatarHeader:
import React from "react";
const WithAvatarHeader = WrappedComponent => props => {
return <WrappedComponent {...props} />;
};
export default WithAvatarHeader;
Thanks for the help :-)
You should not declare component inside another component.
Once you move declaration outside:
const Message = WithAvatarHeader(SimpleMessage);
const MessageList = props => {
return (
<div className="message-list">
{props.messages.map(message => {
return <Message message={message} key={message._id}/>;
})}
</div>
);
};
you will be fine.
Reason is reconciliation process that decides what's to drop, what to create and what to update.
Besides your JSX says it still same element <Message> React checks component's constructor(it does not work with text representation from JSX). And it will referentially different(since you re-declare this constructor on next render). So React drops every <Message> and create them from scratch. Keeping declaration outside your MessageList means constructor is referentially the same so React will not re-create <Message> till key is the same.

How to call functional component from another functionnal component in react js

I have to call a functional component from another functional component So how can I call child functional component from a functional component in react js.
import React from "react";
import TestFunctional from "./TestFucntional";
const TestListing = props => {
const { classes, theme } = props;
const handleClickTestOpen = () => {
return <TestFunctional />;
};
return (
<div>
<EditIcon
className={classes.icon}
onClick={handleClickTestOpen}
/>
</div>
);
};
export default TestListing;
I am trying to call or render TestFucntional component on EditIcon clicked but it is not called. So How can I call component?
Thanks.
You just use it in your jsx as a component as usual. You can see here
const ItemComponent = ({item}) => (
<li>{item.name}</li>)
const Component1 = ({list}) => (
<div>
MainComponent
<ul>
{list && list.map(item =><ItemComponent item={item} key={item.id}/>)}
</ul>
</div>)
const list = [{ id: 1, name: 'aaa'}, { id: 2, name: 'bbb'}]
ReactDOM.render(
<Component1 list={list}/>
, document.querySelector('.container')
);
From the above conversation, I guess you want conditional rendering, i.e. after any event you want to render the child component. To do so in the parent component, it should maintain a state. If you want to use functional parent component, you can use hooks. Or you can use some prop for the conditional rendering as well. Please provide a code snippet.
This is for reference: https://reactjs.org/docs/conditional-rendering.html

Resources