What is the purpose of this.props.onChange()? - reactjs

From the react quickstart: https://facebook.github.io/react/docs/lifting-state-up.html
The purpose of the line:
handleChange(e) {
this.props.onChange(e.target.value);
}
was never explained and I can't figure out what it does. Is onChange a built in method of props? I thought props was simply just parameters for components, why can it invoke functions?

I came here with the same question, but I understand it now (at least I think I do). The issue is that onChange in the Calculator class is a prop, but in the render portion of the class TemperatureInput, it's an event listener. Sometimes I see this in React, where the same name is used on two completely different things, and I find it can easily create confusion. Here's what happens in the following code block:
class TemperatureInput extends React.Component {
handleChange(e) {
this.props.onChange(e.target.value); **(2)**
}
render() {
return (
<fieldset>
<input value={value} onChange={this.handleChange} /> **(3)**
</fieldset>
);
}
}
class Calculator extends React.Component {
handleCelsiusChange(value) {
this.setState({scale: 'c', value});
}
render() {
return (
<div>
<TemperatureInput
scale="c"
value={celsius}
onChange={this.handleCelsiusChange} /> **(1)**
</div>
);
}
}
In Calculator, a made up prop called onChange passes a reference to the method handleCelsiusChange to TemperatureInput
this.props.onChange() in TemperatureInput is now a reference to handleCelsiusChange() in Calculator
onChange={this.handleChange} is an event listener, which will fire handleChange() up on the change of the input field.
In conclusion, onChange as a prop is custom, onChange as an event listener is built in. The prop just passes a function reference from an ancestor to the child so you can run it in the child.

I thought props was simply just parameters for components, why can it invoke functions?
You're right, but those parameters can also be callbacks/functions. E.g:
Definition:
class Comp extends Component {
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
return (<input onChange={this.handleChange.bind(this)) />
}
}
Usage:
<Comp onChange={(a) => console.log(a)} />

Got a clue from SeattleFrey's answer, maybe the author of that code shouldn't name this parameter onchange. It is so confusing for a starter of ReactJs like me.
I name it myChange instead of onChange. It is actually a function passed in as a parameter. And e.target.value is the parameter for that function.Props can contain objects as well as functions, since functions are also objects in Javascript
class TemperatureInput extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.props.myChange(e.target.value);
}
render() {
const value = this.props.value;
const scale = this.props.scale;
return (
<fieldset>
<legend>Enter temperature in {scaleNames[scale]}:</legend>
<input value={value}
onChange={this.handleChange} />
</fieldset>
);
}
}
class Calculator extends React.Component {
handleCelsiusChange(value) {
this.setState({scale: 'c', value});
}
render() {
return (
<div>
<TemperatureInput
scale="c"
value={celsius}
myChange={this.handleCelsiusChange} />
</div>
);
}
}

You just missed this sentence:
If several components need access to the same state, it is a sign that the state should be lifted up to their closest common ancestor instead. In our case, this is the Calculator.
Your quoted code is from component TemperatureInput:
class TemperatureInput extends React.Component {
handleChange(e) {
this.props.onChange(e.target.value);
}
render() {
return (
<fieldset>
<input value={value} onChange={this.handleChange} />
</fieldset>
);
}
}
And TemperatureInput is a child component of Calculator, where TemperatureInput.onChange is assigned to Calculator. handleCelsiusChange
class Calculator extends React.Component {
handleCelsiusChange(value) {
this.setState({scale: 'c', value});
}
render() {
return (
<div>
<TemperatureInput
scale="c"
value={celsius}
onChange={this.handleCelsiusChange} />
</div>
);
}
}

Related

Get value from input component and use it in another component in React

I'm new to React and have this simple code example where I simply need to take value from input and show the value back.
class App extends React.Component {
constructor(props){
super(props);
this.state = { word : ""};
this.onClick = this.onClick.bind(this);
}
onClick(e){
this.setState({word : /* how to obtain input value?? */});
}
render() {
return (
<>
<form>
<input type="text"/>
<button onClick={this.onClick}>Say it!</button>
</form>
<div>
{this.state.word}
</div>
</>
);
}
}
I know react want's me to use component state as a way to propagate information from parent component to it's children. What I don't know is how I should obtain state of a children to be used in another children.
I believe this should be doable in react in simple manner as the equivalent way of doing it using pure DOM or JQuery would also be very simple (one or two lines of code).
You can use createRef
import React, { createRef } from "react";
import "./styles.css";
class App extends React.Component {
constructor(props) {
super(props);
this.state = { word: "" };
this.onClick = this.onClick.bind(this);
}
textInput = createRef();
onClick(e) {
this.setState({ word: this.textInput.current.value });
}
render() {
return (
<div className="App">
<form>
<input ref={this.textInput} type="text" />
<button onClick={this.onClick} type="button">
Say it!
</button>
</form>
<div>{this.state.word}</div>
</div>
);
}
}
export default App;
check here CodeSandBox
A few things here. First I don't see children as you mention. Moreover, you say obtain state of a children to be used in another children. You have just one parent component here. Then, you are using a <form> which means a button inside will submit the values so you need the escape hatch of e.preventDefault(). Finally, if you must use a class based component instead of functional component, you don't need any more constructor and you can bind your functions with an arrow function. Here is a working example of what I presume you are asking: https://codesandbox.io/s/sleepy-minsky-giyhk

react way of setting focus on a particular button in stateful component?

I tried different ways of setting focus to button on pageload like ref ,but it doesnt work. Thats is whenever pageloads focus should be on this button.
Can anyone help me with a sample example
class SubPageHeader extends React.Component {
constructor(props) {
super(props);
}
componentDidMount() {
}
render() {
return (
<input type="button"/>
);
};
}
Can anyone help me with a solution ?
componentDidMount will execute only once when your page loads first time, to maintain a focus on every re-render you also need to use componentDidUpdate.
class SubPageHeader extends React.Component {
constructor(props) {
super(props);
this.myInput = React.createRef();
}
componentDidMount() {
this.myInput.current.focus(); //To focus first time page loads
}
componentDidUpdate(){
this.myInput.current.focus(); //To focus on every re-render
}
render() {
return (
<input type="button" ref={this.myInput} />
);
};
}
Using refs:
class Component extends React.Component{
input = React.createRef()
componentDidMount(){
this.input.current.focus()
}
render(){ return <input ref={this.input} /> }
}
Or plain HTML : <input autoFocus />
To focus on component mount the simplest way is
class SubPageHeader extends React.Component {
render() {
return (
<input autoFocus type="button"/>
);
};
}

Reactjs focus an input field located in a child component which is inside another child component

I am currently trying to focus an input field that is located in a child component which is inside another child component. consider the following,
Parent.js
child1.js
child2.js
I would like to focus input field in child2 when a button is clicked from parent.js.
I don't say using this technique it's good but you can achieve this by creating a setRef function who get pass by the child 1 to the child 2. Make sure to read this https://reactjs.org/docs/refs-and-the-dom.html why refs is not the best thing. For me I would use props callback.
But if you really want to use ref this is how you can do. I put the code example here. You can also play with the code here https://codesandbox.io/s/5x8530j3xn
class Child2 extends React.Component {
render() {
return (
<div>
<input ref={this.props.setRef} />
</div>
);
}
}
class Child1 extends React.Component {
render() {
return (
<div>
<Child2 setRef={this.props.setRef} />
</div>
);
}
}
class Parent extends React.Component {
setRef = ref => {
this.input = ref;
};
focus = () => {
this.input.focus();
};
render() {
return (
<div>
<Child1 setRef={this.setRef} />
<button onClick={this.focus}>Go Focus</button>
</div>
);
}
}
Just use plain vanilla JavaScript inside a React method.
handleFocus () {
document.getElementById('inputField').focus()
}
<button onClick={this.handleFocus}>My Button</Button>
This will focus the input after clicking the button.

Accessing refs in a stateful component doesn't work in React?

I'm currently trying to refactor the simple-todos tutorial for meteor using presentational and container components, but ran into a problem trying to access the refs of an input in a functional stateless component. I found out that to access refs, you have to wrap the component in a stateful component, which I did with the input.
// import React ...
import Input from './Input.jsx';
const AppWrapper = (props) => {
// ... more lines of code
<form className="new-task" onSubmit={props.handleSubmit}>
<Input />
</form>
}
import React, { Component } from 'react';
This Input should be stateful because it uses class syntax, at least I think.
export default class Input extends Component {
render() {
return (
<input
type="text"
ref="textInput"
placeholder="Type here to add more todos"
/>
)
}
}
I use refs to search for the input's value in the encompassing AppContainer.
import AppWrapper from '../ui/AppWrapper.js';
handleSubmit = (event) => {
event.preventDefault();
// find the text field via the React ref
console.log(ReactDOM.findDOMNode(this.refs.textInput));
const text = ReactDOM.findDOMNode(this.refs.textInput).value.trim();
...
}
The result of the console.log is null, so is my Input component not stateful? Do I need to set a constructor that sets a value for this.state to make this component stateful, or should I just give up on using functional stateless components when I need to use refs?
or should I just give up on using functional stateless components when I need to use refs?
Yes. If components need to keep references to the elements they render, they are stateful.
Refs can be set with a "callback" function like so:
export default class Input extends Component {
render() {
// the ref is now accessable as this.textInput
alert(this.textInput.value)
return (
<input
type="text"
ref={node => this.textInput = node}
placeholder="Type here to add more todos"
/>
)
}
}
You have to use stateful components when using refs. In your handleSubmit event, you're calling 'this.refs' when the field is in a separate component.
To use refs, you add a ref to where you render AppWrapper, and AppWrapper itself must be stateful.
Here's an example:
AppWrapper - This is your form
class AppWrapper extends React.Component {
render() {
return (
<form
ref={f => this._form = f}
onSubmit={this.props.handleSubmit}>
<Input
name="textInput"
placeholder="Type here to add more todos" />
</form>
);
}
};
Input - This is a reusable textbox component
const Input = (props) => (
<input
type="text"
name={props.name}
className="textbox"
placeholder={props.placeholder}
/>
);
App - This is the container component
class App extends React.Component {
constructor() {
super();
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
event.preventDefault();
const text = this._wrapperComponent._form.textInput.value;
console.log(text);
}
render() {
return (
<AppWrapper
handleSubmit={this.handleSubmit}
ref={r => this._wrapperComponent = r}
/>
);
}
}
http://codepen.io/jzmmm/pen/BzAqbk?editors=0011
As you can see, the Input component is stateless, and AppWrapper is stateful. You can now avoid using ReactDOM.findDOMNode, and directly access textInput. The input must have a name attribute to be referenced.
You could simplify this by moving the <form> tag into the App component. This will eliminate one ref.

placing child component inside parent in reactjs

I am trying to build a form with custom input fields. Problem is structure of form is not pre known. And i want it to abstract as many common functionalities as i can. So i created a form component which will actually take care of storing value of all input components and action on submit. Rest inside form how html should be that will be written by the user.
here is a snapshot:
a custom input field:
class InputField extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
id: this.props.id,
value: this.props.value || '',
valid: this.props.isValidationRequired || this.props.required ? true : false,
errorVisible: false,
errorMessage: ''
};
}
//different helper and conchange function
render() {
let props = this._getInputFieldProps();
return (<div className={this.props.fieldParentClass}>
<label for={this.props.id}>{this.props.name}</label>
<input {...props}/>
<span className={this.state.errorVisible ? 'show' : 'hide'}>{this.state.errorMessage}</span>
</div>)
}
}
export default InputField;
form:-
class FormComponent extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
submitButton: {
buttonClasses: ['btn-default', 'vy-btn-secondary'],
buttonText: "SUBMIT",
}
};
}
//functions for storing values of children and submit
render() {
return <form role="form" class="vm-form">
<Button disabled={this.state.submitValid} onClick={this._onSubmit.bind(this)} button={this.state.submitButton}></Button>
</form>
}
}
export default FormComponent;
and caller class:-
class LeadDetails extends React.Component {
constructor(HttpService, $state, VymoDataService, props, context) {
super(props, context);
}
render() {
return (<FormComponent >
<InputField placeholder='hi' value="1"
type="text"
id="name"
maxlength="10"></InputField>
</FormComponent>)
}
}
so now i can wrap my input field component in some html wrapper and customise the look the way i want. But here only form is getting render not input field, neither its behaving as child.
Have I got it totally wrong in some way. What should have been my approach?
In your FormComponent render method, you need to render the "children", which will be located on this.props.children:
render() {
return <form role="form" class="vm-form">
{this.props.children}
<Button disabled={this.state.submitValid} onClick={this._onSubmit.bind(this)} button={this.state.submitButton}></Button>
</form>
}
The reason for this is when you go to actually create (instantiate) the form, you are doing the following:
<FormComponent >
<InputField placeholder='hi' value="1"
type="text"
id="name"
maxlength="10"></InputField>
</FormComponent>
The stuff in between the component tags are the "children". The children are passed to your component during instantiation (props.children), it's up to the component to render those children. The reason you are probably expecting the children to be rendered automatically is because React treats <ReactComponents> differently from <normal-dom-elements>.
Whenever react sees a <Tag> which begins with an upper case letter, it assumes that it's a react component and basically converts this:
<Tag foo="bar"><div>hello</div></Tag>
to something like this:
new Tag({
foo: "bar",
children: React.createElement('div', null, "hello")
})

Resources