Reputation: 1119
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
Upvotes: 1
Views: 151
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
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
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