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

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

Related

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

Functional Component's props in Higher Order Component

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

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.

Passing ref to child component to animate with GSAP

I'm new to React and i am trying to integrate GSAP to animate a child component using refs. The process to try and animate worked fine before I seperated out the elements into their different components!
There are no error codes from React, but I do get the following console error:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
I've looked into the forwardRef mentioned but not sure if it's right for what i'm trying to achieve.
/**
* Parent Component
*/
import React, { Component } from 'react';
import Spirit from './Spirit';
import { TweenMax, Power1 } from 'gsap';
class SpiritResults extends Component {
constructor(props) {
super(props);
this.multiElements = [];
}
componentDidMount() {
TweenMax.staggerFromTo(
this.multiElements,
0.5,
{ autoAlpha: 0 },
{ autoAlpha: 1, ease: Power1.easeInOut },
0.1
);
}
render() {
return (
<ul className="mm-results">
{this.props.spirits.map(({ id, title, featImg, link, slug, index }) => (
<Spirit
key={id}
slug={slug}
title={title}
featImg={featImg}
link={link}
ref={li => (this.multiElements[index] = li)}
/>
))}
</ul>
);
}
}
/**
* Child Component
*/
import React from 'react';
const Spirit = ({ slug, link, featImg, title, index }) => (
<li id={slug} className="mm-item" ref={index}>
<a href={link}>
<div className="inner">
<img src={featImg} alt={title} />
<h3>{title}</h3>
</div>
</a>
</li>
);
export default Spirit;
Any tips that can be given to get the animation to work would be appreciated. If there are any better ways of animating react with GSAP please let me know your thoughts.
Thanks
There are a few mistakes here.
ref is not a prop. You can't just pass it to a custom component and access it like props.ref
You're appending the wrong ref inside <li>, index is not a valid ref object
To pass down a ref to a custom component you need to use React.forwardRef and append the ref to your Child's <li>. Something like this
const Parent = () =>{
const ref = useRef(null)
return <Child ref={ref} title='hey i\'m a prop'/>
}
const Child = React.forwardRef((props, ref) =>(
<li ref={ref}>
{props.title}
</li>
))

how to stop re-rendering of list items in context consumer when state changes

I have a react project and I use the context api to manage the app's state.
I have a list of items with an onClick event that updates the state in the context.
The problem is that when the state changes all items re-renders which causes a lag.
My question is how to stop other items from re-rendering if not clicked on.
item.jsx
import React, { useContext } from "react";
import { MainContext } from "../../_context/PresentContext";
const Item = ({item}) => (
<MainContext.Consumer>
{({handleSelectItem}) => (
<div>
<button onClick={() => handleSelectItem(item)}>{item.name}</button>
</div>
)
}
</MainContext.Consumer>
)
items.jsx
import React from "react";
import Item from "./Item";
const itemsList = [
{id: 1, name: 'a'},
{id: 2, name: 'b'},
{id: 3, name: 'c'},
{id: 4, name: 'd'}
]
const Items = () => (
<div>
{itemsList.map(i => (
<Item item={item}/>
)
)}
</div>
)
the handleSelectItem functions just updates selectedItem on the context state and then i use it in a different compnent
this is just a simple example do demonstrate the problem. the real itemsList has about 200 item.
You can extend React.PureComponent if your Item component props are all serializable or you extends React.Component and implement shouldComponentUpdate.
Option 1.
import React, { Component } from "react";
import isEqual from 'lodash.isequal';
export class Item extends Component {
shouldComponentUpdate(nextProps){
return !isEqual(this.props.item, nextProps.item);
}
render() {
const { item } = this.props;
return (
<MainContext.Consumer>
{({ handleSelectItem }) => (
<div>
<button onClick={() => handleSelectItem(item)}>{item.name}</button>
</div>
)}
</MainContext.Consumer>
);
}
}
Option 2
export class Item extends PureComponent {
render() {
const { item } = this.props;
return (
<MainContext.Consumer>
{({ handleSelectItem }) => (
<div>
<button onClick={() => handleSelectItem(item)}>{item.name}</button>
</div>
)}
</MainContext.Consumer>
);
}
}
What about using Pure Components and making decision in life cycle method shouldComponentUpdate?
If you prefer to stick with hooks here is an official documentation how to implement mentioned above life cycle method with hooks approach.
Use React.memo / PureComponent / shouldComponentUpdate to re-render the components only when their state/props change in an immutable manner, instead of being re-rendered just because the parent component re-rendered.
use key attribute in your mapped JSX elements so that React can map between your DOM elements and only re-render them if the key's value change, instead of re-rendering the entire list every time the component is being rendered
arrow functions and object literals return a new reference every time they're called, so its better to define them outside of your render function and use useCallback or useMemo hooks to memoize them. so that they don't break your PureComponent
Consider using react-window https://github.com/bvaughn/react-window to implement virtual scrolling instead of rendering 200 items that might be hidden for the user and dont need to be in the DOM slowing things down
item.jsx
import React, {memo, useContext } from "react";
import { MainContext } from "../../_context/PresentContext";
const Item = memo(({item}) => (
const handleClick => useCallback(handleSelectItem(item), [item])
const renderConsumer = ({handleSelectItem}) => (
<div>
<button onClick={handleClick}>{item.name}</button>
</div>
)
<MainContext.Consumer>
{renderConsumer()}
</MainContext.Consumer>
))
items.jsx
import React, {memo} from "react";
import Item from "./Item";
const Items = memo(() => (
<div>
{itemsList.map(i => (
<Item key={i} item={item}/>
)
)}
</div>
))

Resources