How the render process is going in React? - reactjs

I just starting to get confused about the render process in React.
Let's say I've got a Higher Order Component what looks something like this:
const withHOC = () => WrapperComponent => {
return class WithHOC extends React.Component {
render() {
//someProps => what will change...
//...rest => won't change
const { someProps, ...rest } = this.props
return(
<WrapperComponent {...rest} />
)
}
}
}
This is where I am quite confused...
as someProps will change the HOC itself will re-render. Is this means the WrappedComponent will be re-rendered as well?
I mean the WrappedComponent's props not changing.
And how expensive can this be?

React HOC is not a big deal to understand when you think it as just a parent component.
Now, guess what happens when child component receive the props from the parent component?
The child component will be re-rendered.
What happens to the parent component render?
The parent component is also re-rendered because its props changes.
The same thing applies to the HOC. Thus, WrapperComponent will also re-render whenever the props / state changes.

Related

how to update both parent and child state before render without extra renders in React 15

If I use setState in the child and place a callback in the parent to update the parent state that propagates to child props, then I end up with two render calls.
One for the update to the child state, and one for the prop changing. I can manually use shouldComponentUpdate to ignore the prop change if I want, but the render won't be ready until the state updates.
I know all this can be done easily in react 16-18, but migrating is not simple at the moment.
I am wondering if the solution is to make the child state the source of truth. I can solve all my problems this way, but I thought in react you typically made the parent the source of truth.
Parent Component
Child Component
ChildComponent
function = () => {
this.setState ( {updatedStateProperty}, callback())
}
ParentComponent
callback = () => {
this.setState ( {propSentToChild})
}
What happens is the child component changes state, then render occurs, then the callback occurs, prompting another render.
I want to either
A. change child state, then have the callback called before render
or
B. update child state, then ignore the parents passed props
I can do B, but I'm unsure whether it is proper form to basically make the child's version of the shared state the source of truth
I think you're kind of close. What you really want to do is pass the state to the parent, handle setting the state there, and let the new state trickle down to your child component via props. This is a fairly common pattern for react.
class Parent extends React.Component {
constructor() {
this.state = { foo: "bar", bing: "baz" }
}
stateUpdater(newState) {
this.setState({ ...this.state, ...newState });
}
render() {
return <Child
prop1={this.state.foo}
prop2={this.state.baz}
stateUpdater={this.stateUpdater}
/>
}
}
class Child extends React.Component {
handleClick = () => {
this.props.stateUpdater({ foo: 'bazaar' });
}
render() {
return <div>
The foo is {this.props.foo} and the baz is {this.props.baz}.
<button onClick={this.handleClick}>Click Me!</button>
</div>
}
}

useState with arrays not rerendering

I am facing issue while using useState hook with array. I checked various resources on stackoverflow, but could not fix it.
my basic code snippet looks like :
const [users, setUsers] = useState([]);
function addNewContact(user) {
const newUsers = [...users,user];
console.log(newUsers);
setUsers(newUsers);
}
<CardContainer users={users}></CardContainer>
class CardContainer extends Component {
constructor(props) {
super(props);
console.log("this -> ");
console.log(this.props.users);
this.state = {
users: this.props.users
}
}
render() {
//console.log(this.state.users)
return (
<div class="row row-cols-1 row-cols-md-2 g-4">
{
this.state.users.map(user => {
return <Card id={user.phone} title={user.name} email={user.email} phone={user.phone}></Card>
})
}
</div>
)
}
}
export default CardContainer;
I am able to see updated array in the console, but the component using it is not rendering again. Can anyone please help me on this.
The issue is due to you're storing the prop in the state of the child component, which is assigned on component initialization and component initialization/constructor only run one, until its remounted. After that, whenever, the state changes in the parent component, the child component is not re-rendering, because it uses its own state for map.
This below code only runs once on the component initialization.
this.state = {
users: this.props.users
}
In the child component, you can directly use the props and the child component will always re-render on change in the parent component. Instead of this.state.users.map you can directly map the array from props like this this.props.users.map. This way,the component will re-render on state change in the parent compoenent.
As #Junaid said, constructor is only called once before component mounting. If you really need to set a separate state inside the child component, then you can use componentDidUpdate(prevProps) react life cycle method. Make sure to compare previous and current props in order to avoid infinite loop of re-rendering.
componentDidUpdate(prevProps) {
if (this.props.users !== prevProps.users) {
this.setState({ users: this.props.users });
}
};

How to pass props from functional component to class component

I'm quite new to functional components and I've been on this for hours.
I simply want to pass a prop from a parent functional component to a class child component so that I will use the updated prop (which will be a boolean) to change the display of an element. That's all.
In this scenario, I want to switch the sidenav from opened to closed based on the prop.
Here is the parent component (functional):
let opened = false;
function openSidenav(){
opened = !opened;
}
const [sidebarOpened, setOpened ] = useState(opened);
return (
<Sidebar sidebarOpened={opened} />
)
and the child component (class):
componentDidUpdate(prevProps) {
if(this.props.sidebarOpened !== prevProps){
this.setState({ sidebar: true});
}
}
It's just not working, the child component isn't receiving changes, I guess I didn't pass the prop rightly. I know the code just needs correction but I don't know where I'm not getting it.
Thank you.
The argument to useState is only used once. You need to set the state in openSidenav function to trigger a re-render.
Parent
function openSidenav(){
setOpened(prev => !prev);
}
const [sidebarOpened, setOpened ] = useState(false);
return (
<Sidebar sidebarOpened={sidebarOpened} />
)
Also in child component, use prevProps.sidebarOpened (not just prevProps).
Child
componentDidUpdate(prevProps) {
if(this.props.sidebarOpened !== prevProps.sidebarOpened){ //<---- see here
this.setState({ sidebar: this.props.sidebarOpened});//<---- see here
}
}
p.s - Also, since you are using props directly in child component, you can consider to not to copy props into state.
In parent,
const [sidebarOpened, setOpened ] = useState(false);
function openSidenav(){
setOpened(!sidebarOpened);
}
return (
<Sidebar sidebarOpened={sidebarOpened} />
)
And in child component class directly use this.props.sidebarOpened instead of copying over the prop to state. If you intend to edit the value of sidebarOpened in the child component, pass setOpened to the child component as a prop and use that to edit the value.

Unmounting a component when triggered through parent component

I have a parent component and child component. Child component will be rendered through parent based on a condition. So, when child gets rendered, all useEffect and other code gets executed and I'm able to achieve componentDidMount kind of methods. I'm not directly accessing child component but only use Parent to render it based on parent's props.
Once my child component is visible, I call a method which resets 'doesChildExists' prop and re-render ParentComponent and since the condition is failed, ChildComponent is not rendered (unmounted). Once, ChildComponent is about to unmount, I need to do some stuff, but existing useEffect doesn't seem to get called. How do I handle this? Please help!!
Please, let me know if this is not the right approach, and I have handle rendering of child in a different way.
const ChildComponent: FunctionComponent<Props> = (props: Props) => {
useEffect(() => {
return () => {
// handle unmount
}
}, []);
return (
<div class='textDiv'>
This is content
</div>
)
}
const ParentComponent: FunctionComponent<ParentProps> = (props: ParentProps) => {
return (
<>
{doesChildExists &&
createPortal(<ChildComponent />, document.body)}
</>
)
}

Will react re-render only children in which some part of the state has changed or are all children that use the state are re-rendered?

Consider the following scenario in a component.
export default class Dummy extends React.Component{
state = {
A: some data
B: other data
C: extra data
}
somefunction = () => {
this.setState({A: changed Data});
}
render(){
return(
<ChildA data={this.state.A} callBackFunction={this.somefunction}/>
<ChildB data={this.state.B}/>
<ChildC data={this.state.C}/>
);
}
}
That is, if State 'A' is changed, will ChildA only be re-rendered (because it is only associated with 'A') or all the children be re-rendered (because they are associated with state in general)?
Theoretically this some function will invoke render method which result in rendering of all child components.
Try should component updates, useMemo, React.memo etc to control the defending of individual components.

Resources