How do I access a child node in React? - javascript

I am using React Modal.
I'm doing something like this:
React.createClass({
render() {
return <ReactModal
isOpen={true}
>{content}</ReactModal>
}
});
Now {content} might have an input field inside. I know I can't use ref in this case. If I use getDOMNode, that can get me the wrapper, but I don't know of an easy way to find a child by class name. Am I supposed to use native code there?

React components are js objects only. In worst case if you want to access the child you can print the component in your browser console and expand it. You can see the child components, from there also you can access refs and all.

Related

Why use refs in react? What is the use cases for it?

This question exists but it didn't give a lot of data or real world explanation: What are Refs in React or React-Native and what is the importance of using them
Let's say i want to integrate to 3rd party library how ref is going to help me?
Some 3rd party libraries expose methods to interact with their components.
For example, in react-native-elements npm, they have shake method for Input component. You can use this method to shake Input element when user input is invalid.
Common use case is as follows:
import React from 'react';
import { Input, Button } from 'react-native-elements';
const [value, setValue] = useState('');
const input = React.createRef();
return (
<View>
<Input
ref={input}
onTextChange={(text) => setValue(text)}
/>
<Button
title={'Submit'}
onPress={() => {
if (!isValid(value)) {
input.current.shake();
}
}}
/>
</View>
);
This is react native example, but the similar goes to react projects. I hope you get the picture. Animations like shake cannot be easily handled with state, so it's better to use useRef to call component methods directly.
Let's say i want to integrate to 3rd party library how ref is going to help me?
Refs let you access the DOM directly, thus you can use vanilla js libraries using refs, for example you could use jQuery like $(ref). This simplifies and makes getting DOM nodes less error prone than using other techniques such as adding classes/ids to every element and then using selectors since these methods do not stop you from accessing nodes not created by you.
Long story short, Refs let you treat react elements as though they were vanilla js
React useRef help us to accessing dom elements before its rendering.
You can go through it
https://reactjs.org/docs/refs-and-the-dom.html
Whenever you want to use the properties of child from a parent, we refer it with a ref id, this is to ensure we are executing on the right child component. The properties can be either states, props of functions defined in the child component.

React ref to pass through child rendered as this.props.children

I have a simple React component that wraps another and provides some resizing ability.
I'm having trouble getting a ref to the single child passed to Resizer. There doesnt seem to be an elegant way to ask React for a ref to a pass through child, even when assuming this.props.children is a single node.
Any ideas?
Usage
<Resizer>
<MyColumn />
</Resizer>
<MyBody />
Resizer.js
...
render() {
return ([
this.props.children, // <== I need a ref to this component's DOM node
<div className="resizer--class"></div>
])
}
Caveats:
I dont want to force consumers to pass node refs to <Resizer>
I dont want to wrap <MyColumn /> in an extra <div>
This works, but alters the HTML structure:
<div ref={this.assignChildRef}>{this.props.children}</div>
I dont want to store any state in flux
I dont want to use a DOM workaround like node.previousSibling even though this technically would get me the child node

Is it possible to achieve something like HOC with classes - without classes in React?

I want to do something like:
<SomeProvider showConfirm={showConfirm}>
{props.showConfirm()
? (<confirmActionComponent />)
: (<chooseActionComponent />)}
</SomeProvider>
Inside of chooseActionComponent I want to be able to access showConfirm or another value in a deep nested child component to update some value in the parent and have confirmActionComponent show.
I know how to achieve this using class which tends to involve this and bind at some point, and I would prefer to avoid that.
Is there any way to accomplish something like this using pure functions/components instead? Would also prefer to keep this out of Redux store.
If you just want to access showConfirm, you simply can pass it to the child:
<SomeProvider showConfirm={showConfirm}>
{props.showConfirm()
? (<confirmActionComponent />)
: (<chooseActionComponent showConfirm={showConfirm} />)}
</SomeProvider>
Note following quote from React docs to inheritance:
At Facebook, we use React in thousands of components, and we haven't found any use cases where we would recommend creating component inheritance hierarchies.
Anyway, I maybe have a really really dirty hack for you...
use ref...
const Child = () =>
<div ref={(self) => {
// get ReactDOMNode on stateless component
const ReactDOMNode = self[Object.keys(self).filter((key) =>
/__reactInternalInstance/g.test(key))[0]];
// access parent props
console.dir(ReactDOMNode
._hostParent
._currentElement
._owner
._currentElement
.props);
}}></div>;
Note: that this is not recommended and I won't recommend that, too.
I would advice you to simply pass needed parent props to the child.
<SomeProvider showConfirm={showConfirm}>
{props.showConfirm()
? (<confirmActionComponent />)
: (<chooseActionComponent showConfirm={showConfirm} />)}
</SomeProvider>
And in your chooseActionComponent you can:
const chooseActionComponent = ({parentProps: {showConfirm}}) =>
<div>{showConfirm}</div>;
You do not have to use ES6 classes to create React content. If you would like to avoid having to repeatedly use bind to ensure correct scoping of methods (that use this.setState / this.props), you can revert back to using the React API helper functions (see React without ES6).
You can specifically use: React.createClass for creating React classes and HOCs. Again, just to re-iterate this: using this alternative syntax will autobind this for you.

React: Bubbling up click events on nested components

I'm creating a react file tree, and I have the tree setup as a React component. The tree can take a contents prop that is an array of either strings, or other <Tree /> components (this enables the nested file structure UI). These tree components can be nested indefinitely.
I need to register a click event on the children of the nested tree components, but I'm having trouble getting it to work beyond the first level of nesting. A simplified example of what I'm dealing with:
//In App - the top level component
const App = React.createClass({
_handleChildClick () {
console.log("this is where all child clicks should be handled");
},
render () {
return (
<Tree
handleChildClick={this._handleChildClick}
contents={[
<Tree />
]}
/>
);
}
});
//And in the tree component
<div onClick={this.props.handleChildClick}></div>
If you want to see more detail - here's the github repo.
I tried researching this question and saw people using {...this.props} but I'm not sure if that applies to my scenario - if it does, I couldn't get it to work.
Thanks for any help on this.
The reason why the click handling does not work beyond the first level is because your second level Tree component (the one inside the contents array) does not get the appropriate prop handleChildClick passed in. (BTW I think the convention is to call the prop onChildClick while the handler function is called handleChildClick - but I digress.)
Do I understand correctly that you actually want to inform each layer from the clicked component up to the top? For this to happen, you need to extend the props of the tree component that is inside the contents array - it needs to receive the click handler of its parent component. Of course, you cannot write this down statically, so it needs to be done dynamically:
Your Tree component, before actually rendering its children, should extend each of them with the component's click handler, which can be done using the function React.cloneElement (see API documentation and a more detailed discussion). Directly applying this to your component makes things a bit messy, because you are passing the component's children in a prop, so you need to figure out which prop to modify. A bit of a different layout would help you quite a lot here:
<Tree handleChildClick={this._handleChildClick}>
<Tree />
</Tree>
looks nicer IMHO and makes the structure much clearer. You can access the inner components via this.props.children, and cloneElement will be much simpler to use.
So, in your Tree component, you could have a render method like this:
render () {
const newChildren = this.props.children.map(child =>
React.cloneElement(child, {onChildClick: this._handleChildClick}));
return (
<div>{newChildren}</div>
);
}
Please note that this code will not work if you have a mixture of strings and Tree components, therefore my third and last suggestion would be to wrap those strings into a very thin component to allow for easier handling. Alternatively, you can of course do a type comparison inside the map.

React.js: Difference between passing in the subcomponents with React.render() and with React.createClass()'s render?

I'm working on a project using React.js, and very confused about the composition of React.
http://facebook.github.io/react/docs/multiple-components.html
the link above gives an example. It uses React.creatClass() create three components. A parent component and two child components. The parent component includes the others within it's JSX in the render method.
This example's very clear, but not very 'reusable'. What if I wanna pass in another child in another situation? React.js seems lacking the 'extend' method like Backbone's view.
later, I found that you can pass children components in the React.render(), and use this.props.children to composite.
var Tom = React.createClass({
render: function(){
return(
<a>This is Tom.</a>
)
}
});
var John = React.createClass({
render: function(){
return(
<a>This is John.</a>
)
}
});
var Outter = React.createClass({
componentDidMount:function(){
console.log(this.props.children);
},
render: function(){
return(
<div className="test">
{this.props.children}
</div>
)
}
});
React.render(<Outter><Tom /><John /></Outter>, document.getElementById('main'));
I think that's great but what's the really difference between this method and the example above? is this method the right way to composite components in React.js?
thanks
The difference is just like you said, that you can pass any components you'd like as children of that component. Components that use this.props.children are usually components that acts as wrappers for style and behaviour, but the contents of the component changes for different use cases. Like a popup, where you want the same look and behaviour (like a close button) for every popup, but the contents of the popup is different for every popup.
Components that don't use this.props.children are more like black boxes, they know everything about how they should be rendered and what child components they need. But you can still make them dynamic by passing other props to them.
Components can be also be passed as props. Components are just JS objects, and any JS object can be passed as a prop. But I don't think I've ever seen a use case for doing it. It might make some sense if you have a wrapper component with two or more specific "slots" that should be rendered to. Something like:
var Wrapper = require('./wrapper');
var Header = require('./title');
var Content = require('./content');
var Footer = require('./footer');
var MyComponent = React.createClass({
render() {
return <Wrapper footer={Footer} header={Header} content={Content} />;
}
});
It depends on your use-case, take this two examples of forms:
a login form - almost all login forms have the same structure, username/email, password, a keep me logged in checkbox, and a login button; a LoginForm component doesn't need to be further customised in regards to its structure so it's suitable to be used as is
a signup form - now depending on context you might give more or less fields to the user to complete when signing up, and in this case you use props.children

Categories