Is it a way to change the children of a component dynamically? I have a component which wraps other components, recursively walks the children, what I want is to change the text of the childrens that are string. e.g.
render() {
const func = (node) => {
React.Children.forEach(node.children, (childNode) => {
if (childNode && childNode.props && typeof childNode.props.children === "object") {
func(childNode.props);
}
else if (typeof childNode.props.children === "string"){
console.log(childNode.props);
}
})
}
func(this.props);
return <span>{ this.props.children }</span>;
}
Setting childNode.props.children === "something" inside the else is failing, children is read-only. Any idea how I can achieve what I want?
React props are read only indeed as it stated in React docs. You can follow JSX approach, which always creates new element, instead of changing existing element props. At later stage element is reconciled with existing React component in the Virtual DOM.
To change props of the element via JavaScript you can clone element using React.cloneElement method. Please note, you should not render this.props.children in this case, instead render new resulting element tree:
render() {
const func = (children) => {
return React.Children.map(children, (childNode) => {
if (typeof childNode === "string")
return "something"; // cover case: <div>text<div></div></div>
if (typeof childNode.props.children === "string")
return React.cloneElement(childNode, [], "something");
return React.cloneElement(childNode, [], func(childNode.props.children));
})
}
return <span>{ func(this.props.children) }</span>;
}
I'd suggest having dynamic children list in state of the component and render them.
JSFiddle
class Hello extends React.Component {
constructor() {
super();
this.state = {
children: [
<div>test</div>,
<div>test2</div>
]
};
setTimeout(() => {
this.setState({
children: [
<div>new!</div>,
<div>changed!</div>
]
});
}, 2000);
}
render() {
return <p>{this.state.children}</p>;
}
}
ReactDOM.render(
<Hello />,
document.getElementById('container')
);
You can apply this concept in your app.
The solution would be to iterate over the this.props.children
and to create the custom children like this.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = { no: 'need' };
}
render() {
let children = []; // children
let k = 0; // key
this.props.children.forEach( function(child) {
if( "string" === typeof child.props.children ){
console.log(child);
let enew = React.cloneElement( child, child.props, "new_" + k );
k++;
children.push(enew);
}else{
children.push(child);
}
});
return <span>{ children }</span>;
}
}
var NewComponent = React.createClass({
render: function() {
return (
<div className="awesome" style={{border: '1px solid red'}}>
Hello World!
</div>
);
}
});
ReactDOM.render(
<Parent>
<NewComponent />
<div>Hello</div>
<div>World</div>
</Parent>,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Based on your need you may even create new element instead of cloning the existing one.
let enew = React.createElement( 'div', {key: k, className: 'new'}, "new" );
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With