1

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

CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
Amir Rahman
  • 1,076
  • 1
  • 6
  • 15
  • Does this answer your question? [How to pass props to {this.props.children}](https://stackoverflow.com/questions/32370994/how-to-pass-props-to-this-props-children) – Quentin Grisel Feb 08 '22 at 22:55
  • Could you explain your need better? If I did not intend to change the, I’m of active from the parent component? Did I understand well? – user1175801 Feb 09 '22 at 07:46
  • i am trying to make like a radio button where child element will be active based on click rest should reset to inactive but the logic is in parent component so parent component will check all childs and set props and interface of that whole component should simple and no logic should writtern in use time – Amir Rahman Feb 10 '22 at 09:07

3 Answers3

1

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.

Quentin Grisel
  • 4,794
  • 1
  • 10
  • 15
  • This is not ideal. Cloning an element creates a new version of that element and initializes it with new component state. Whenever this parent component re-renders, the child will get re-initialized instead of re-rendered. There is an important difference between the two. If you had a `useState()` hook in the child for example, this state would get reset. – Bugbeeb Feb 08 '22 at 23:13
  • @Bugbeeb It doesn't seem to erase the state. You can check my stackblitz, I edited it to try what you said and everything is kept. – Quentin Grisel Feb 08 '22 at 23:24
  • I stand corrected, it seems to transfer component state to the clone – Bugbeeb Feb 08 '22 at 23:32
  • For no misleading interpretation, I'll add that there is also no problem with the existing props. – Quentin Grisel Feb 08 '22 at 23:34
1

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>
    )
}
Bugbeeb
  • 2,021
  • 1
  • 9
  • 26
0

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}})
   ))
}
  • "TypeError: Cannot add property active, object is not extensible" this is the error i am facing thats why i have posted – Amir Rahman Feb 08 '22 at 22:52