I have two JS files included in page as utility.js and utility1.js Code for utility.js
var HelloWorld = React.createClass({
render: function() {
return (
<p>
Hello, <input type="text" ref="mytestinput" placeholder="Your name here" />!<br />
It is {this.props.date.toTimeString()}
</p>
);
}
});
setInterval(function() {
React.render(
<HelloWorld date={new Date()} />,
document.getElementById('container')
);
}, 1000);
Code for utility1.js
var MyComponent = React.createClass({
handleClick: function() {
// Explicitly focus the text input using the raw DOM API.
React.findDOMNode(HelloWorld.refs.mytestinput).focus();
},
render: function() {
// The ref attribute adds a reference to the component to
// this.refs when the component is mounted.
return (
<div>
<input type="text" ref="myTextInput" />
<input
type="button"
value="Focus the text input"
onClick={this.handleClick}
/>
</div>
);
}
});
React.render(
<MyComponent />,
document.getElementById('container1')
);
The problem here is I want focus on input of HelloWorld Component of utility.js from utility1.js. I saw their is one method as findDOMNode for mounted components. But this code is not working for me. Can Somebody try this JS Fiddle here and let me know possible solution.
You need to create the global event system in order to allow both components communicate with each other if they are not in parent-child relationship. Here is more information about global event system
Here is the solution: jsfiddle
var CustomEvents = (function() {
var _map = {};
return {
subscribe: function(name, cb) {
_map[name] || (_map[name] = []);
_map[name].push(cb);
},
notify: function(name, data) {
if (!_map[name]) {
return;
}
// if you want canceling or anything else, add it in to this cb loop
_map[name].forEach(function(cb) {
cb(data);
});
}
}
})();
var HelloWorld = React.createClass({
componentDidMount: function() {
React.findDomNode(this.refs.mytestinput).focus()
},
...
});
or if your React.js is up-to-date, use this:
componentDidMount() {
this.refs.mytestinput.focus()
}
Refs are local to the component they are defined on, so HelloWorld.refs.mytestinput is not valid. Furthermore, since MyComponent and HelloWorld are part of two different React applications (created by two different calls to React.render), there's no built-in way to access the refs in HelloWorld from MyComponent. You would need to set some kind of global reference to the component, use message passing from one app to the other, emit events of some kind indicating the input should be focused, or use some other method of "global" communication.
Just use
this.refs.myTextInput
https://jsfiddle.net/e0cjqLu2/
Related
I have component A and B. Component A pass state as prop to component, says it's named show
so in my component B's render function it will be like this
{this.props.show &&
<div>popup content</div>
}
But how I close it now? I have to pass a flag from component B to the parent? as I know it react you can pass stuff back to parent.
In order to pass data from a child to a parent, the parent needs to pass a function capable of handling that data to the child.
var Parent = React.createClass({
getData: function(data){
this.setState({childData: data});
}
render: function(){
return(
<Child sendData={this.getData} />
);
}
});
var Child = React.createClass({
textChange: function(event){
this.setState({textString: event.target.value});
}
buttonClick: function(){
this.props.sendData(this.state.textString);
}
render: function(){
<div>
<input type="text" value={this.state.textString}
onChange={this.textChange}/>
<button onClick={this.buttonClick}
</div>
}
});
There are other ways of handling data, and it might be worth your while creating a data store to store global variables and handle various events. In this way you would keep the data flow of your application one way. In smaller scale cases however, this solution should suffice.
Use the eventBus to send/receive date from child/parent components respectively.
Example below:
class Date extends Component {
constructor(props) {
super(props);
this.state = {
date:'',
}
this.callback = this.callback.bind(this); // register callback method
}
callback(date){ // callback method to receive data
this.setState({date: date});
}
componentDidMount(){
EventBus.on("date", this.callback);
}
render() {
<div>
{this.state.date}
</div>
}
}
From any other component
handleDayClick(day) {
EventBus.publish("date", day);
}
https://github.com/arkency/event-bus
I have two components, a parent and a child like so:
class Parent extends React.Component {
shuffle() {
...
}
blur() {
...
}
next() {
...
}
previous() {
...
}
render() {
return (
<Child Parent={this} />
);
}
}
class Child extends React.Component {
constructor(props) {
super();
this.state = {};
this._onShuffleClick = this._onShuffleClick.bind(props.Parent);
this._onPreviousClick = this._onPreviousClick.bind(props.Parent);
this._onNextClick = this._onNextClick.bind(props.Parent);
}
_onShuffleClick(event) {
event.preventDefault();
this.shuffled ? this.shuffle(false) : this.shuffle(true); // I can call parents method here as the 'this' context is the 'Parent'.
this.blur(event.target);
this.setState({test "test"}); //I can set the parents state here
}
_onPreviousClick(event) {
event.preventDefault();
this.previous();
this.blur(event.target);
}
_onNextClick(event) {
event.preventDefault();
this.next();
this.blur(event.target);
}
render() {
return (
<a className="shuffle" key={1} onClick={this._shuffleOnClick}>{this.props.Parent.props.html.shuffle}</a>,
<a className="previous" key={2} onClick={this._previousOnClick}>{this.props.Parent.props.html.previous}</a>,
<a className="next" key={3} onClick={this._nextOnClick}>{this.props.Parent.props.html.next}</a>,
);
}
}
Is passing the context ('this' keyword) as a prop an anti-pattern?
Is setting the state of the parent from the child bad?
If I do this I then don't have to pass a lot of individual props to the child and I can also set the state of the parent from the child.
You can interact with the state of a parent from a child-component, but probably not the way you are trying to achieve this.
If you want to send in all props of the parent down to a child, you can do:
<Child {...this.props} />
This way, you don't need to specify each individual prop one at a time; instead, you just send them all in. Check out the spread operator here and here for more info. More info also on MDN:
The spread syntax allows an expression to be expanded in places where multiple arguments (for function calls) or multiple elements (for array literals) or multiple variables (for destructuring assignment) are expected.
If you want to access or modify the state of a parent from a child you have to do this slightly differently. Typically, you would create a function that does this interaction with the state in your parent and then send that function as a prop down to the child. Like this:
Parent:
_modifyState = (bar) => {
this.setState({foo: bar});
}
.....
<Child modifyState={this._modifyState} />
Child:
this.props.modifyState("Hello world!");
The above will set state.foo in the parent to the string Hello world! from the child component.
If you want access to all state variables, you could send it in as a prop to the child (the whole object) and then have a function (like above) which modifies the entire state (not just one property) - depends what you want really.
Well, it's mainly a bad usage of passing around the props, you could also go for {...props} instead, and I wouldn't want to pass it through the full name, you can also use let { props } = this; let parentProps = props.Parent.props. The question is also, why would you refer to parent props, that seems the bad practise, divide and conquor, only pass the props that are really needed, and do not assume in your child components that a certain parent component is available
When you pass event handlers down, let those eventhandlers be bound to your current this, but don't bind them in the child to an expected parent, a bit like this example
var StyledButton = React.createClass({
propTypes: {
clickHandler: React.PropTypes.func.Required,
text: React.PropTypes.string.required
},
render: function() {
let { clickHandler, text } = this.props;
return <button type="button" onClick={clickHandler}>{text}</button>;
}
});
var MyForm = React.createClass({
click: function() {
alert('ouch');
},
render: function() {
return <fieldset>
<StyledButton clickHandler={this.click} text="Click me" />
</fieldset>
}
})
ReactDOM.render(
<MyForm />,
document.getElementById('container')
);
<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="container">
<!-- This element's contents will be replaced with your component. -->
</div>
Yes I do think your code is bad practice. Now you chid components know about the parent component which makes your child impure.
When your parent implementation changes, the child components will break because of this.props.Parent.props.html.previous}.
I think each react component should update the parent by calling the parents functions passed by the props.
class Parent extends React.Component {
doSomethingBeacauseTheChildStateHasChanged() {
// function
}
render() {
<Child doSomething={doSomethingBeacauseTheChildStateHasChanged.bind(this)}/>
}
}
class Child extends React.Component {
render() {
<button onClick={this.props.doSomething}>Child button</button>
}
}
Note: I am not an expert and React beginner, treat this as an opinion rather than guideline.
I think yes cause you force particular implementation. What would you do if you wanted to have those methods in GrandParent? If you use props this modification is really easy, but with your implementation it would be pain in the ass.
There is also a feature called PropTypes. It's really great to make components reusable, but it's yet another thing you can't use if you do the things like you have proposed.
Maybe it is just me but this also creates a great confusion. You should pass everything you need as props.
Also setting parent state like this
this.setState({test "test"}); //I can set the parents state here
seems bad to me. I would rather pass a function from parent as a prop and bind parent before passing it down.
You can trigger a function in the Parent. This is the correct way to a children communicates with its parent.
class Parent extends React.Component {
shuffle(e) {
console.log(e.target);
return false;
}
render() {
return (
<Child onShuffle={this.shuffle} />
);
}
}
class Child extends React.Component {
render() {
return(
<a href='#' onClick={this.props.onShuffle}>Shuffle</a>
);
}
}
Child.propTypes = {
onShuffle: React.PropTypes.func
}
I am unable to use something like this.refs.child.state in my application to access state of a child component, hence need an alternative way to do so. Main reason for this is to pass child contents to redux state when a certain button is clicked inside such childs parent component, hence function in parent component needs to pass childs content as one of the parameters.
Depending on the structure of your components (hard to tell when you don't post code), you could fix this just by chaining callbacks via props. I.e.
var Parent = React.createClass({
onChange: function(childValue){
this.setState({childValue: childValue});
},
render: function(){
return <Child onChange={this.onChange} />
}
});
var Child = React.createClass({
handleChange: function(event){
this.props.onChange(event.target.value);
},
render: function(){
return <input onChange={this.handleChange}/>
}
});
Add in as many middle-layers as needed of the form;
var MiddleChildA = React.createClass({
render: function(){
return <MiddleChildB onChange={this.props.onChange} />
}
});
Is there any way passing state from parent component to child component like:
var ParentComponent = React.createClass({
getInitialState: function() {
return {
minPrice: 0
}
},
render: function() {
return (
<div onClick={this.doSomething.bind(this, 5)}></div>
);
}
});
var ChildComponent = React.createClass({
getInitialState: function() {
return {
minPrice: // Get from parent state
}
},
doSomething: function(v) {
this.setState({minPrice: v});
},
render: function() {
return (
<div></div>
);
}
});
I want to change parent state value from child component. In react.js is it possible or not?
There is but it's not intended to work like that in React.
2-way data binding isn't the way to go in React, excerpt from the docs.
In React, data flows one way: from owner to child.
So what you want to do if you want to manipulate parent state in your child component is passing a listener.
//parent component's render function
return (
<Child listenerFromParent={this.doSomething} />
)
//child component's render function
return (
<div onClick={this.props.listenerFromParent}></div>
)
You can use the limelights solution, ie passing a function from the parent to the child.
Or you can also use projects like React-Cursor which permits to easily manipulate state passed from a parent component in a child.
I have made my home made framework (Atom-React, some details here) that also use cursors (inspired by Om), and you can somehow achieve easily 2-way data binding with cursors permitting to manipulate the state managed by a parent component.
Here's an exemple usage:
<input type="text" valueLink={this.linkCursor(this.props.inputTextCursor)}/>
The inputTextCursor is a cursor passed from a parent to a child component, and thus the child can easily change the data of the parent seemlessly.
I don't know if other cursor-based React wrappers use this kind of trick but the linkCursor function is implemented very easily with a simple mixin:
var ReactLink = require("react/lib/ReactLink");
var WithCursorLinkingMixin = {
linkCursor: function(cursor) {
return new ReactLink(
cursor.getOrElse(""),
function setCursorNewValue(value) {
cursor.set(value);
}
);
}
};
exports.WithCursorLinkingMixin = WithCursorLinkingMixin;
So you can easily port this behavior to React-Cursor
Since React doesn't have any builtin way to manage document.title, I used to set it inside componentDidMount of my route handlers.
However now I need to amend the title based on state fetched asynchronously. I started putting assingments into componentDidUpdate, but every now and then I forget to put document.title assignment into some pages, and previous title sticks around until I finally notice it.
Ideally I'd like a way to express document.title declaratively, without having to assign it. Some kind of “fake” component would probably be most convenient, given that I want to be able to specify the document title at several nesting levels:
On top level (the default title);
On page level (for some of the pages, but not all);
Sometimes, on inner component level (e.g. user typing into a field).
Additional requirements:
Title specified in child should override title specified by parent;
Reliable (guarantees cleanup on route change);
Should not emit any DOM (i.e. no hacks with component returning <noscript>);
I'm using react-router but it's better if this component works with other routers too.
Anything I can use?
I wrote react-document-title just for that.
It provides a declarative way to specify document.title in a single-page app.
If you want to get title on server after rendering components to string, call DocumentTitle.rewind().
Features
Does not emit DOM, not even a <noscript>;
Like a normal React compoment, can use its parent's props and state;
Can be defined in many places throughout the application;
Supports arbitrary levels of nesting, so you can define app-wide and page-specific titles;
Works on client and server.
Example
Assuming you use something like react-router:
var App = React.createClass({
render: function () {
// Use "My Web App" if no child overrides this
return (
<DocumentTitle title='My Web App'>
<this.props.activeRouteHandler />
</DocumentTitle>
);
}
});
var HomePage = React.createClass({
render: function () {
// Use "Home" while this component is mounted
return (
<DocumentTitle title='Home'>
<h1>Home, sweet home.</h1>
</DocumentTitle>
);
}
});
var NewArticlePage = React.createClass({
mixins: [LinkStateMixin],
render: function () {
// Update using value from state while this component is mounted
return (
<DocumentTitle title={this.state.title || 'Untitled'}>
<div>
<h1>New Article</h1>
<input valueLink={this.linkState('title')} />
</div>
</DocumentTitle>
);
}
});
Source
I keep track of mounted instances and only use title given to the top DocumentTitle in the mounted instance stack whenever it updates, gets mounted or unmounted. On server, componentWillMount fires but we won't get didMount or willUnmount, so we introduce DocumentTitle.rewind() that returns a string and destroys state to prepare for next request.
var DocumentTitle = React.createClass({
propTypes: {
title: PropTypes.string
},
statics: {
mountedInstances: [],
rewind: function () {
var activeInstance = DocumentTitle.getActiveInstance();
DocumentTitle.mountedInstances.splice(0);
if (activeInstance) {
return activeInstance.props.title;
}
},
getActiveInstance: function () {
var length = DocumentTitle.mountedInstances.length;
if (length > 0) {
return DocumentTitle.mountedInstances[length - 1];
}
},
updateDocumentTitle: function () {
if (typeof document === 'undefined') {
return;
}
var activeInstance = DocumentTitle.getActiveInstance();
if (activeInstance) {
document.title = activeInstance.props.title;
}
}
},
getDefaultProps: function () {
return {
title: ''
};
},
isActive: function () {
return this === DocumentTitle.getActiveInstance();
},
componentWillMount: function () {
DocumentTitle.mountedInstances.push(this);
DocumentTitle.updateDocumentTitle();
},
componentDidUpdate: function (prevProps) {
if (this.isActive() && prevProps.title !== this.props.title) {
DocumentTitle.updateDocumentTitle();
}
},
componentWillUnmount: function () {
var index = DocumentTitle.mountedInstances.indexOf(this);
DocumentTitle.mountedInstances.splice(index, 1);
DocumentTitle.updateDocumentTitle();
},
render: function () {
if (this.props.children) {
return Children.only(this.props.children);
} else {
return null;
}
}
});
module.exports = DocumentTitle;
Take a look at the NFL's react-helmet.
class Layout extends React.Component {
constructor(props){
super(props);
document.title = this.props.title;
}
render(){
return(
<div>
</div>
);
}
}
and then <Layout title="My Title"/> that easy!
Try react-frozenhead, it's actually more sophisticated than react-document-title - it allows us change title, description and anything else in section.
Meanwhile, 3 years have gone! ;-)
If you want to manipulate other page headers than title (like description, canonical, etc.), react-document-meta NPM dependency could be a good thing to use.