My component is used inside other render() like
return (<MyElem>Some text here</MyElem>)
How can I access the "Some text here" string inside my component's class?
You use the children property, which contains the children of your element (which might be text or an array of children [I think it's always an array when it's not text], see the link for the gory details). E.g.:
const Foo = props => {
console.log(props.children);
return (
<div>{props.children}</div>
);
};
ReactDOM.render(
<Foo>Hi There</Foo>,
document.getElementById("react")
);
<div id="react"></div>
<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>
That uses a stateless functional component (SFC), but it's the same for Component subclasses:
class Foo extends React.Component {
render() {
console.log(this.props.children);
return (
<div>{this.props.children}</div>
);
}
};
ReactDOM.render(
<Foo>Hi There</Foo>,
document.getElementById("react")
);
<div id="react"></div>
<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>
Here's an example of the fact that children isn't just for text:
class Foo extends React.Component {
render() {
console.log(this.props.children);
return (
<div>{this.props.children}</div>
);
}
};
ReactDOM.render(
<Foo>
<div>Hi there</div>
<Foo><span>nested Foo > Foo > span</span></Foo>
</Foo>,
document.getElementById("react")
);
<div id="react"></div>
<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>
Add a ref to To MyElem:
<MyElem ref="elem">My text here<MyElem>
Then you can refer to your element elsewhere with:
this.refs.elem
Related
How can I append or change the className prop with React.cloneElement?
When I use React.cloneElement I'm unable to change or append the className prop. I've searched for hours but I found nothing. React.Children.only or removing the spread don't change the behavior. It appear to be a bug, or a performance optimization feature?.
Expect html: <div class="parent"><div class="child other-class">testing...</div></div>
Result html: <div class="parent"><div class="child">testing...</div></div>
Class example:
class Parent extends React.Component {
render() {
return (
<div className={"parent"}>
{React.cloneElement(React.Children.only(this.props.children), {
...this.props.children.props,
className: `${this.props.children.props.className} other-class`,
})}
</div>
);
}
}
class Child extends React.Component {
render() {
return <div className={"child"}>{"testing..."}</div>;
}
}
Functional component example:
const Parent = ({ children }) => (
<div className={"parent"}>
{React.cloneElement(React.Children.only(children), {
...children.props,
className: `${children.props.className} other-class`,
})}
</div>
);
const Child = () => <div className={"child"}>{"testing..."}</div>;
const Parent = ({ children }) => (
<div className={"parent"}>
{React.cloneElement(React.Children.only(children), {
...children.props,
className: `${children.props.className} other-class`,
})}
</div>
);
const Child = () => <div className={"child"}>{"testing2..."}</div>;
ReactDOM.render(
<React.StrictMode>
<Parent>
<Child />
</Parent>
</React.StrictMode>,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
The problem is that you're never using className in Child, which is what you're manipulating in Parent. Child puts a className on a div, but that isn't Child's className, it's just a hardcoded one that Child puts on the div.
If you want Child to put that class on the div, you have to write the code to do that. Also, you don't need the spread, the props are merged. Finally, to get the original className, I'd use the result of calling Children.only, rather than going back to this.props.children (though that will work because only would throw if there weren't only one).
See comments:
class Parent extends React.Component {
render() {
// Get the `className` from the child after verifying there's only one
const child = React.Children.only(this.props.children);
const className = `${child.props.className} other-class`;
return (
<div className={"parent"}>
{React.cloneElement(child, {
// No need to spread previous props here
className,
})}
</div>
);
}
}
class Child extends React.Component {
render() {
// Use `className` from `Child`'s props
const className = (this.props.className || "") + " child";
return <div className={className}>{"testing..."}</div>;
}
}
// Note the `classname` on `Child`, to show that your code using
// `this.props.children.props.className`
ReactDOM.render(<Parent><Child className="original"/></Parent>, document.getElementById("root"));
.child {
color: red;
}
.child.other-class {
color: green;
}
.original {
font-style: italic;
}
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
In my application, I have a requirement to render same data into multiple places via react.
So instead of rendering that via id (via below code), i want to use class tag.
ReactDOM.render(<App />, document.getElementById('app')); // Working
ReactDOM.render(<App />, $('.app')); // Not working.
My html is like below...
<div class="app" id="app"><div>
<div class="app"><div>
<div class="app"><div>
Update: below is my jsx file.
class PList extends React.Component {
static defaultProps = {
results: []
}
constructor(props) {
super(props);
this.state = {
results: this.props.results
};
}
render() {
return (
<ul>
{
this.state.results.map((item, i) => {
return <li>{item.Name}</li>
})
}
</ul>
);
}
}
var PRender = ReactDOM.render(<PList />, $('.app'));
function Professionals(data) {
PRender.setState({
results: data.Results
});
}
$('.app') - this is just an array, and ReactDOM.render requires single element as second parameter.
You can try as following if you need to render multiple App.
function App({index}) {
return `<div>App - ${index}</div>`;
}
document.querySelectorAll('.app').forEach((app, index) => ReactDOM.render(<App index={index + 1} />, app));
<html>
<div id="app">No ID assigned to App</div>
<div class="app"></div>
<div class="app"></div>
<div class="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</html>
Here's the answer for your edition.
https://codesandbox.io/s/hopeful-payne-1tloe?fontsize=14
Same as #Alona's answer. I tried to use jQuery -> $('.app') which described on question.
function App({index}) {
return `<div>App - ${index}</div>`;
}
$.each($('.app'), (index, app) => ReactDOM.render(<App index={index + 1} />, app))
<html>
<div class="app" id="app"></div>
<div class="app"></div>
<div class="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
</html>
function Clock(props) {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {props.date.toLocaleTimeString()}.</h2>
</div>
);
}
function tick() {
ReactDOM.render(
<Clock date={new Date()} />,
document.getElementById('root')
);
}
setInterval(tick, 1000);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Question:
people, please explain the below code, here how are we moving to the second function like{without kind of any callback function}?
You can achieve this by moving your setInterval up in your component and use it to update its state to make it re-render.
Also, reactDOM.render should only ever be called once.
Working example :
class Clock extends React.Component{
state = { date: new Date() }
componentDidMount(){
setInterval(() => { this.setState({ date: new Date() })}, 1000);
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I am trying to go through object properties (Name for this example) and list them within easy loop in function. I have found some pretty awkward way of doing this but it doesn't seem right.
Here is what i got:
const ItemsToSell = [{"Name":"Cup","Price":"99.99"},{"Name":"IPhone","Price":"99.99"},{
"Name":"Pen","Price":"99.99"}]
function ListItem(props) {
return <li>{props.value}</li>;
}
function NumberList(props) {
const a = props.numbers;
return (
<ul>
{a.map((number) =>
<ListItem value={ItemsToSell[number].Name} />
)}
</ul>
);
}
const numbers = [0,1, 2];
ReactDOM.render(
<NumberList numbers={numbers} />,
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>
Is there a better way to do this?
I simply need a loop to go through array of objects, list needed properties and create one of many html nodes.
You can simply map over ItemsToSell array
const ItemsToSell = [{"Name":"Cup","Price":"99.99"},{"Name":"IPhone","Price":"99.99"},{
"Name":"Pen","Price":"99.99"}]
function ListItem(props) {
return <li>{props.value}</li>;
}
function NumberList(props) {
return (
<ul>
{ItemsToSell.map((obj, index) =>
<ListItem key={index} value={obj.Name} />
)}
</ul>
);
}
ReactDOM.render(
<NumberList />,
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>
Why don't you iterate over ItemsToSell array? You don't have to add yet another one.
Note: Include key property while looping the elements, else you will receive an error.
const ItemsToSell = [{"Name":"Cup","Price":"99.99"},{"Name":"IPhone","Price":"99.99"},{
"Name":"Pen","Price":"99.99"}]
function ListItem(props) {
return <li>{props.value}</li>;
}
function NumberList(props) {
return (
<ul>
{ItemsToSell.map((elem, index) =>
<ListItem value={elem.Name} key={index} />
)}
</ul>
);
}
ReactDOM.render(
<NumberList />,
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>
I am defining tooltip as
<MACDTooltip ref="MACDTooltip" forChart={chartId} forDataSeries={dataSeriesId} key={`${chartId}-${dataSeriesId}`} calculator={macdCalculator}
onClick={logger.bind(null, { chartId, dataSeriesId }, options)} origin={[-48, 15]}/>
but in componentDidMount() method
ReactDOM.findDOMNode(this.refs.MACDTooltip).getAttribute("transform")
return null
ReactDOM.findDOMNode(this.refs.MACDTooltip)
returns
<g><g class="react-stockcharts-toottip" transform="translate(-48, 15)"...</g></g>
and
ReactDOM.findDOMNode(this.refs.MACDTooltip).innerHTML
return "<g class="react-stockcharts-toottip" transform="translate(-48, 15)"></g>
How do i use ReactDOM.findDOMNode to get proper value
Since the g tags are nested, you want to find the childNode of it and get the attribute from there. Example:
class Example extends React.Component {
componentDidMount() {
console.log(
ReactDOM.findDOMNode(this.refs.MACDTooltip).childNodes[0].getAttribute('transform')
);
}
render() {
return(
<MACDTooltip ref="MACDTooltip" />
);
}
}
// Sample MACDTooltip class for demo.
class MACDTooltip extends React.Component {
render() {
return(
<g>
<g transform="Attribute"><text>Tooltip</text></g>
</g>
);
}
}
ReactDOM.render(<Example />, document.getElementById('View'));
<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="View"></div>