Amir Rahman
Amir Rahman

Reputation: 1119

React Parent To Child Component Props Update Issue

Let say i have two components one parent and another child now i have a prop in child component called active which basically assign {active} class to child if its true now i wanted to change this prop from its parent component while rendering. take a look at some codes below

main code

import React from 'react';
import { List , Item } from "../Buttons";

export function Sample2() {
    return (
        <List>
            <Item>items</Item>
            <Item>items</Item>
            <Item>items</Item>
        </List>
    )
}

component codes

commented line is what i am trying to achieve but its not allowed

export function List({ children }){
    const [index,setIndex] = useState(0)

    function getOptions(){
        return children.map((each,i)=>{
            //each.props.active = index == i
            return each
        })
    }

    return (
        <div className="list">
            {getOptions()}
        </div>
    )
}

export function Item({ active , children }){
    const classes ="item p-4 border-b" + (active?` active`:"")
    return (
        <div className={classes}>{children}</div>
    )
}

now i wanted to know what is the way to achive this or i am not following react flow ? i am old in javascript but very much new to react so please explain what would be the best way to achive this

here's a screenshot of my codes enter image description here

Upvotes: 1

Views: 151

Answers (3)

Quentin Grisel
Quentin Grisel

Reputation: 4987

Already tagged as duplicate, but for fast comprehension, here is how to do it :

import React, { Component } from "react";
import { render } from "react-dom";
import "./style.css";

const App = () => {
  return (
    <List>
      <Item>Element</Item>
      <Item>Element</Item>
      <Item>Element</Item>
    </List>
  );
};
const List = ({children}) => {
  const clonedChild = () => children.map((c, i) => React.cloneElement(c, {isActive: i === 0 ? 'active' : ''}))
  return (
    <>
    {clonedChild()}
    </>
  )
}

const Item = ({isActive}) => <div className={isActive ? 'active' : ''}>Item</div>

render(<App />, document.getElementById("root"));

.active {
  background-color: brown;
}

An here is the repro on Stackblitz.

Upvotes: 1

Bugbeeb
Bugbeeb

Reputation: 2151

A React component should never modify it's own props directly. If you think about a component as a function, modifying a parameter being passed to the function by the caller means you cannot run the same function twice and guarantee it will output the same result. This is necessary for React's rendering cycle to behave correctly. Therefor you need to set the props via element attributes like <MyComponent message={foo} /> where foo is a variable declared within the parent. An easy way to accomplish what you want is to provide a prop to the each child in the list:

export function List({ children }){
    const [index,setIndex] = useState(0)

    return (
        <div className="list">
            {children.map((child, i)=> (
                <Item isActive={index === i}>
                  {child}
                </Item>
               )
            )}
        </div>
    )
}

Upvotes: 1

Tunahan Bayındır
Tunahan Bayındır

Reputation: 489

React is a declarative paradigm. It would be better if you don't mutate the each. Instead:

function getOptions(){
 return React.Children.map(children, 
   (child, i) => (
     React.cloneElement(child, {active: index === i}})
   ))
}

Upvotes: 0

Related Questions