Correct way to inherit React components - javascript

I understand that my question is a little bit biased, but I am very new in Javascript and prototypes, and I read about it, but I don't really understand how to apply that techniques to my practical problems. So an example would be very helpful.
So I have a React component, that basically looks like that:
var Component1 = React.createClass({
getInitialState: function () {
return ({
searchable: true,
})
},
function1: function () {
return ({
somevalue
})
},
render: function () {
var redText = {
color: 'red'
};
var redBorder = {
color: 'red',
border: '1px solid red'
};
return (
<form>
<div>
<a onClick={this.props.handleAddClick}>Something</a>
</div>
<div>
<label>Some label</label>
<input type="text"/>
</div>
</form> )
});
I also have Component2 which is basically absolutely the same, but has one additional <input/> inside the return of its render function.
I also have Component3, which shares same functions, but has different render() function.
So how to apply inheritance here and avoid copy-paste 3 times? I just miss some practical illustration, so I'd appreciate it.
Edit1____________________________________________________
So I tried to implement Prototype inheritance as per the first answer, but it seems React doesn't see these functions: getInitialState() is null, initial state is null after rendering. What's wrong with this approach?
I also tried to go according to the textbook and did:
function MyPrototype() {};
MyPrototype.prototype.getInitialState = function () {
return ({
someProperty: true;
})
};
function Component1() {};
Component1.prototype = Object.create(MyPrototype.prototype);
Component1.prototype.render = function () {
console.log(this);
return (<div></div>)};
var MyComponent1 = React.createClass(new Component1());
But when I open my browser, I get an error: Uncaught Invariant Violation: createClass(...): Class specification must implement arendermethod.
What am I doing wrong this way?
Edit2_______________________________________________
Actually, I see that React doesn't support mixins neither prototypes. Composition should be used instead. It's explained in this article:
Dan Abramov's article Mixins Are Dead. Long Live Composition

In React, inheritance for components is severely discouraged.
React is much better suited for expressing the same relationships via composition.
Here is an example of using composition:
class Button extends Component {
render() {
return (
<div className='Button' style={{ color: this.props.color }}>
{this.props.children}
</div>
)
}
}
class DeleteButton extends Component {
render() {
return (
<Button color='red'>Delete</Button>
)
}
}
Note how DeleteButton uses the look and feel of Button without inheriting from it. Instead, Button defines its configurable parts via props, and DeleteButton supplies those props. In the actual DOM, both <Button /> and <DeleteButton /> would render to a single DOM node—the recursive resolution happens at the render() time, and this is the core idea of React.
In fact, if you don’t need lifecycle hooks or local state, you may even define components as functions:
function Button({ color, children }) {
return (
<div className='Button' style={{ color }}>
{children}
</div>
)
}
function DeleteButton() {
return (
<Button color='red'>Delete</Button>
)
}
You can even mix classes with functions. This would be impossible with inheritance, but works great with composition.
As for your specific use cases:
I also have Component2 which is basically absolutely the same, but has one additional <input/> inside the return of its render function.
You can have your Component1 accept this.props.children and use them in the return value of render() method, and have Component2 render to <Component1><input /></Component>. This is very similar to what I showed above. You also don’t have to use the children prop—you can pass a React element in any prop, e.g. <Component1 footer={<input />} />, and then you can use this.props.footer inside Component1.
I also have Component3, which shares same functions, but has different render() function.
If they share any other code (e.g. utilities that calculate some data), move that code outside components into a shared module, and import it from both components.
If they share any UI, extract it into yet another component, and use it from both your components.

Related

Pass state from class component to function component in react

I have a class where I declare:
constructor() {
super();
this.state = {
checked: false,
house: [],
selectedHouse: null
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(checked) {
this.setState({ checked });
}
render() {
return (
<React.Fragment>
<TSwitch handleChange={this.handleChange.bind(this)} house={this.state.house} houseClicked={this.h}></TSwitch>
</React.Fragment>
);
}
I then want to set state.checked from a child component:
function TSwitch(props) {
const handleChange = (house) => (evt) => {
props.handleChange(house);
};
return (
<div>
{props.house.map((house) => {
return (
<label>
<span>Switch with default style</span>
<Switch onChange={handleChange} checked={this.state.checked} />
</label>
);
})}
</div>
);
}
I am able to call handleChange but I want to be able to change the value of state.checked from the <TSwitch/> component.
This is what your parent component should be like:
constructor() {
super();
this.state = {
checked: false,
house: [],
selectedHouse: null
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(checked) {
this.setState({ checked });
}
render() {
return (
<React.Fragment>
<TSwitch handleChange={this.handleChange} isChecked={this.state.checked} house={this.state.house}></TSwitch>
</React.Fragment>
);
}
This is what your child component should look like:
function TSwitch(props) {
return (
<div>
{props.house.map((house) => {
return (
<label>
<span>Switch with default style</span>
<Switch onChange={x => props.handleChange(x)} checked={props.isChecked} />
</label>
);
})}
</div>
);
}
NOTE: You are using a Switch component, I'm not sure if the variable x will be a boolean or an object, but most probably it should be a boolean: true or false. If this doesn't work, log the value of x & see if its an object, and pass the boolean in props.handleChange. Although I still think this won't be needed. Good luck!
1.
Let's start with your direct question
I want to be able to change the value of state.checked from the <TSwitch/> component
1.1 You've correctly passed your mutator function handleChange from the Parent class to TSwitch but your abstraction function handleChange inside that child, that you've duplicated, is unnecessary and should be removed completely.
1.2 Next, going back to the class' handleChange function, you need to modify the handleChange function definition in the parent component, by fixing the argument you passed it -- which will be the event object, passed implicitly since you registered it as a callback to onChange={handleChange} inside Tswitch. At invocation time, it will be called, and the evt argument that's given to onChange from React, will be passed into handleChange. But, you don't need it. It carries no information of necessity to you. So I would ignore it entirely.
// # parent component
handleChange(evt) {
// NOTE: i'm going to ignore the evt, since I don't need it.
// NOTE: i'm going to use optional callback given by setState, to access prevState, and toggle the checked state boolean value.
this.setState((prevState) => ({ checked: !prevState.checked }));
}
2.
Now let's clean up your code and talk about some best practices
2.1 You dont' need to be using React.Fragment here. Why? because Fragments were introduced in React 16 to provide a declarative API for handling lists of components. Otherwise, they're unecessary abstractions. Meaning: if you're not directly dealing with sibling components, then you don't need to reach for React.Fragment just go with a <div/> instead; would be more idiomatic.
2.2. If <TSwitch></TSwitch> isn't going to have a direct descendent, then you should change your usage syntax to <TSwitch/>.
2.3 If 2.2 didnt' get picked up by a linter, then I highly advised you install one.
2.4 You can continue using explicit bindings of your class handlers in your constructor if you'd like. It's a good first step in learning React, however, there's optimal ways to remove this boilerplate via Babel's transform properties plugins.
This will work:
handleChange(checked) {
this.setState({ checked:!checked });
}

React alternative components definition syntax

I am the kind of person that do not see positively the "class" keyword in the Javascript language as I feel that it does not fit well with the underlying object model. To create objects, I also prefer factories over "new" and constructor functions.
Besides, I really like React. So I have come up with a way of defining components that completely avoids the whole "class" and "extends" thing and only uses functional components or component factories. It also completely avoids to have to bind class methods or to use tricky class properties defined as arrow functions (for event handlers defined as class methods).
Before describing it, here is my question: is it future-proof to use this syntax, or will React one day force me to use a syntax that I do not approve?
Here is how I define components depending on the needs :
Components that only depend on their props are written as functional components (function that returns JSX):
const Comp = (props) => (
<p> Hey { props.name } </p>
);
Comp.propTypes = {
name: PropTypes.string.isRequired
};
Components for which one wants to use lifecycle hooks but that do not maintain any state are written as a function that creates and returns an object whose members are the props, the needed lifecycle methods and the render method:
const Comp = (props) => ({
props,
componentWillMount() {
this.props.doSomething();
},
render() {
return (
<p> Hey { this.props.name } </p>
);
}
});
Comp.propTypes = {
doSomething: PropTypes.function.isRequired,
name: PropTypes.string.isRequired
};
Components that need to maintain state are written as a function that creates and returns an object whose prototype is React.Component (to gain the setState function) and whose members are the props, the state, the needed lifecycle methods and the render method. Functions called by the interface are defined in this factory function closure and act on the component (mainly setState) directly using the component instance (no binding problem here):
const Comp = (props) => {
const comp = Object.create(React.Component.prototype);
const handleClick = () => {
comp.setState((prevState) => ({ value: prevState.value + 1 }));
};
return Object.assign(comp, {
props,
state: { value: 4 },
componentWillUpdate() {},
render() {
return (
<p> Hey { this.props.name } </p>
<p> Value: { this.state.value } </p>
<button onClick={ handleClick }> Increment </button>
);
}
});
};
Comp.propTypes = {
name: PropTypes.string.isRequired
};

Is passing the "this" context through props an anti-pattern?

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
}

How to get the value of an input field using ReactJS?

I have the following React component:
export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
var title = this.title;
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};
The console is giving me undefined - any ideas what's wrong with this code?
There are three answers here, depending on the version of React you're (forced to) work(ing) with, and whether you want to use hooks.
First things first:
It's important to understand how React works, so you can do things properly (protip: it's super worth running through the React tutorial on the React website. It's well written, and covers all the basics in a way that actually explains how to do things). "Properly" here means that you're not writing a web page, you're writing the user interface for an application that happens to be rendered in a browser; all the actual user interface work happens in React, not in "what you're used to from writing a web page" (this is why React apps really are "apps", not "web pages").
React applications are rendered based off of two things:
the component's properties as declared by whichever parent creates an instance of that component, which the parent can modify throughout its lifecycle, and
the component's own internal state, which it can modify itself throughout its own lifecycle.
What you're expressly not doing when you use React is generating HTML elements and then using those: when you tell React to use an <input>, for instance, you are not creating an HTML input element, you are instead telling React to create a React input object that happens to render as an HTML input element when you compile your React app for the web, with event handling that is controlled by React.
When using React, what you're doing is generating application UI elements that present the user with (often manipulable) data, with user interaction changing the state of your application in a way that you define - actions performed by the user may update a component's props or state, which React uses as a signal to generate a new UI representation for changed components, which may cause an update of part of your application interface to reflect the new state.
In this programming model, the app's internal state is the final authority, rather than "the UI your users look at and interact with": if a user tries to type something in an input field, and you did not write anything to handle that, nothing will happen: the UI is a reflection of the application state, not the other way around. Effectively, the browser DOM is almost an afterthought in this programming model: it just happens to be a super convenient UI framework that the entire planet is virtually guaranteed to have access to (but it's not the only one React knows how to work with)
A specific example
So with that covered, let's look how a user interacting with an input element works in React. First, we need to get to having a UI element for the user to interact with:
You wrote a component to manage (i.e. both store and present) some string data for your users, with an onChange function for handling user data.
Your component's rendering code is used by React to generate a virtual DOM that contains an input component (not a DOM <input> element), and binds your onChange handler to that component so that it can be called with React event data (so note that this is not a DOM change event listener, and does not get the same event data that regular DOM event listeners do).
The React library then translates that virtual DOM into a UI users can interact with, and that it will update as the application state changes. Since it's running in the browser, it builds an HTML input element.
Then, your user tries to actually interact with that input element:
Your user clicks on the input element and starts typing.
Nothing happens to the input element yet. Instead, the input events get intercepted by React and killed off immediately.
React turns the browser event into a React event, and calls the onChange function for the virtual DOM component with the React event data.
That function may do something, based on what how you wrote it, and in this case you almost certainly wrote it to update the state of your component with what the user (tried to) type.
If a state update gets scheduled, React will run that state update in the near future, which will trigger a render pass after the update.
During the render pass, it checks to see if the state is actually different, and if so, it generates a temporary second virtual DOM, which it compares to (a part of) your application's virtual DOM, determines which set of add/update/remove operations it needs to perform on you application's virtual DOM so that it looks the same as the new temporary one, then applies those operations and throws away the temporary virtual DOM again.
It then updates the UI so that it reflects what the virtual DOM now looks like.
And after all of that, we finally have an updated DOM on the page the user is actually looking at, and they see what they typed in the input element.
So this is completely different from the regular browser model: instead of the user updating the UI data by typing into a text box first and our code reading "the current value of that text box" to figure out what the state is second, React already knows what the state is, and uses events to update the state first, which leads to a UI update second.
And it is important to remember that all of this happens effectively instantly, so to your user it looks like they typed text into an input element in the same way they would for any random web page, but under the hood things couldn't be more different while still leading to the same result.
So, with that covered, let's look at how to get values from elements in React:
Component classes and ES6 (React 16+ and 15.5 transitional)
As of React 16 (and soft-starting with 15.5) the createClass call is no longer supported, and class syntax needs to be used. This changes two things: the obvious class syntax, but also the thiscontext binding that createClass can do "for free", so to ensure things still work make sure you're using "fat arrow" notation for this context preserving anonymous functions in onWhatever handlers, such as the onChange we use in the code here:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.reset();
}
reset() {
// Always set the initial state in its own function, so that
// you can trivially reset your components at any point.
this.state = {
inputValue: ''
};
}
render() {
return (
// ...
<input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
// ...
);
},
updateInputValue(evt) {
const val = evt.target.value;
// ...
this.setState({
inputValue: val
});
}
});
You may also have seen people use bind in their constructor for all their event handling functions, like this:
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
...
}
render() {
return (
...
<element onclick={this.handler}/>
...
);
}
Don't do that.
Almost any time you're using bind, the proverbial "you're doing it wrong" applies. Your class already defines the object prototype, and so already defines the instance context. Don't put bind of top of that; use normal event forwarding instead of duplicating all your function calls in the constructor, because that duplication increases your bug surface, and makes it much harder to trace errors because the problem might be in your constructor instead of where you call your code.
"But then it's constantly making and throwing away functions on rerenders!" and that may be true but you're not going to notice. Nor are your users. If event handler garbage collection is your performance bottleneck, so much has already gone wrong that you need to stop and rethink your design: the reason React works so incredibly well is because it does not update the entire UI, it only updates the parts that change, and in a well designed UI, the time that most of your UI spends not changing drastically outnumbers the time small parts of your UI spend updating.
Function components with hooks (React 16.8+)
As of React 16.8 the function component (i.e. literally just a function that takes some props as argument can be used as if it's an instance of a component class, without ever writing a class) can also be given state, through the use of hooks.
If you don't need full class code, and a single instance function will do, then you can now use the useState hook to get yourself a single state variable, and its update function, which works roughly the same as the above examples, except without the "universal" setState function call and using one dedicated state setter for each value you're working with:
import { useId, useState } from 'react';
function myFunctionalComponentFunction(props) {
const id = useId();
const [input, setInput] = useState(props?.value ?? '');
return (
<div>
<label htmlFor={id}>Please specify:</label>
<input id={id} value={input} onInput={e => setInput(e.target.value)}/>
</div>
);
}
Previously the unofficial distinction between classes and function components was "function components don't have state", so we can't hide behind that one anymore: the difference between function components and classes components can be found spread over several pages in the very well-written react documentation (no shortcut one liner explanation to conveniently misinterpret for you!) which you should read so that you know what you're doing and can thus know whether you picked the best (whatever that means for you) solution to program yourself out of a problem you're having.
React 15 and below, using legacy ES5 and createClass
To do things properly, your component has a state value, which is shown via an input field, and we can update it by making that UI element send change events back into the component:
var Component = React.createClass({
getInitialState: function() {
return {
inputValue: ''
};
},
render: function() {
return (
//...
<input value={this.state.inputValue} onChange={this.updateInputValue}/>
//...
);
},
updateInputValue: function(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
So we tell React to use the updateInputValue function to handle the user interaction, use setState to schedule the state update, and the fact that render taps into this.state.inputValue means that when it rerenders after updating the state, the user will see the update text based on what they typed.
addendum based on comments
Given that UI inputs represent state values (consider what happens if a user closes their tab midway, and the tab is restored. Should all those values they filled in be restored? If so, that's state). That might make you feel like a large form needs tens or even a hundred input forms, but React is about modeling your UI in a maintainable way: you do not have 100 independent input fields, you have groups of related inputs, so you capture each group in a component and then build up your "master" form as a collection of groups.
MyForm:
render:
<PersonalData/>
<AppPreferences/>
<ThirdParty/>
...
This is also much easier to maintain than a giant single form component. Split up groups into Components with state maintenance, where each component is only responsible for tracking a few input fields at a time.
You may also feel like it's "a hassle" to write out all that code, but that's a false saving: developers-who-are-not-you, including future you, actually benefit greatly from seeing all those inputs hooked up explicitly, because it makes code paths much easier to trace. However, you can always optimize. For instance, you can write a state linker
MyComponent = React.createClass({
getInitialState() {
return {
firstName: this.props.firstName || "",
lastName: this.props.lastName || ""
...: ...
...
}
},
componentWillMount() {
Object.keys(this.state).forEach(n => {
let fn = n + 'Changed';
this[fn] = evt => {
let update = {};
update[n] = evt.target.value;
this.setState(update);
});
});
},
render: function() {
return Object.keys(this.state).map(n => {
<input
key={n}
type="text"
value={this.state[n]}
onChange={this[n + 'Changed']}/>
});
}
});
Managed to get the input field value by doing something like this:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
username : ''
}
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
updateInput(event){
this.setState({username : event.target.value})
}
handleSubmit(){
console.log('Your input value is: ' + this.state.username)
//Send state to the server code
}
render(){
return (
<div>
<input type="text" onChange={this.updateInput}></input>
<input type="submit" onClick={this.handleSubmit} ></input>
</div>
);
}
}
//output
//Your input value is: x
You should use constructor under the class MyComponent extends React.Component
constructor(props){
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
Then you will get the result of title
In react 16, I use
<Input id="number"
type="time"
onChange={(evt) => { console.log(evt.target.value); }} />
Give the <input> a unique id
<input id='title' ...>
and then use the standard Web API to reference it in the DOM
const title = document.getElementById('title').value
No need to continually update the React state with every keypress. Simply get the value when it's required.
In Function Component
useState
Returns a stateful value, and a function to update it.
During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
src ---> https://reactjs.org/docs/hooks-reference.html#usestate
useRef
useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
src ---> https://reactjs.org/docs/hooks-reference.html#useref
import { useRef, useState } from "react";
export default function App() {
const [val, setVal] = useState('');
const inputRef = useRef();
const submitHandler = (e) => {
e.preventDefault();
setVal(inputRef.current.value);
}
return (
<div className="App">
<form onSubmit={submitHandler}>
<input ref={inputRef} />
<button type="submit">Submit</button>
</form>
<p>Submit Value: <b>{val}</b></p>
</div>
);
}
In Function Component :-
export default function App(){
const [state, setState] = useState({
value:'',
show:''
});
const handleChange = (e) => {
setState({value: e.target.value})
}
const submit = () => {
setState({show: state.value})
}
return(
<>
<form onSubmit={()=>submit()}>
<input type="text" value={state.value} onChange={(e)=>handleChange(e)} />
<input type="submit" />
</form>
<h2>{state.show}</h2>
</>
)}
export default class App extends React.Component{
state={
value:'',
show:''
}
handleChange=(e)=>{
this.setState({value:e.target.value})
}
submit=()=>{
this.setState({show:this.state.value})
}
render(){
return(
<>
<form onSubmit={this.submit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<input type="submit" />
</form>
<h2>{this.state.show}</h2>
</>
)
}
}
I succeeded in doing this by binding this to the function
updateInputValue(evt) with
this.updateInputValue = this.updateInputValue.bind(this);
However input value={this.state.inputValue} ...
turned out to be no good idea.
Here's the full code in babel ES6 :
class InputField extends React.Component{
constructor(props){
super(props);
//this.state={inputfield: "no value"};
this.handleClick = this.handleClick.bind(this);
this.updateInputValue = this.updateInputValue.bind(this);
}
handleClick(){
console.log("trying to add picture url");
console.log("value of input field : "+this.state.inputfield);
}
updateInputValue(evt){
//console.log("input field updated with "+evt.target.value);
this.state={inputfield: evt.target.value};
}
render(){
var r;
r=<div><input type="text" id="addpixinputfield"
onChange={this.updateInputValue} />
<input type="button" value="add" id="addpix" onClick={this.handleClick}/>
</div>;
return r;
}
}
your error is because of you use class and when use class we need to bind the functions with This in order to work well. anyway there are a lot of tutorial why we should "this" and what is "this" do in javascript.
if you correct your submit button it should be work:
<button type="button" onClick={this.onSubmit.bind(this)} className="btn">Save</button>
and also if you want to show value of that input in console you should use var title = this.title.value;
This simplest way is to use arrow function
Your code with arrow functions
export default class MyComponent extends React.Component {
onSubmit = (e) => {
e.preventDefault();
var title = this.title;
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};
React Version: 17.0.1
a) Using Functional Components
b) Manage state using hook: useState().
Write and Run code as above:
import React, {useState} from 'react';
const InputElement = () => {
const [inputText, setInputText] = useState('');
return (
<div>
<input
onChange={(e) => {
setInputText(e.target.value);
}
}
placeholder='Enter Text'
/>
{inputText}
</div>
);
}
The solving scheme algorithm is similar to a two-way data binding:
input <=> DATA_MODEL <=> Label_Text
// On the state
constructor() {
this.state = {
email: ''
}
}
// Input view ( always check if property is available in state {this.state.email ? this.state.email : ''}
<Input
value={this.state.email ? this.state.email : ''}
onChange={event => this.setState({ email: event.target.value)}
type="text"
name="emailAddress"
placeholder="johdoe#somewhere.com" />
You can get an input value without adding 'onChange' function.
Just add to the input element a 'ref attr:
And then use this.refs to get the input value when you need it.
Change your ref into: ref='title' and delete name='title'
Then delete var title = this.title and write:
console.log(this.refs.title.value)
Also you should add .bind(this) to this.onSubmit
(It worked in my case which was quite similar, but instead of onClick I had onSubmit={...} and it was put in form ( <form onSubmit={...} ></form>))
if you use class component then only 3 steps- first you need to declare state for your input filed for example this.state = {name:''}. Secondly, you need to write a function for setting the state when it changes in bellow example it is setName() and finally you have to write the input jsx for example < input value={this.name} onChange = {this.setName}/>
import React, { Component } from 'react'
export class InputComponents extends Component {
constructor(props) {
super(props)
this.state = {
name:'',
agree:false
}
this.setName = this.setName.bind(this);
this.setAgree=this.setAgree.bind(this);
}
setName(e){
e.preventDefault();
console.log(e.target.value);
this.setState({
name:e.target.value
})
}
setAgree(){
this.setState({
agree: !this.state.agree
}, function (){
console.log(this.state.agree);
})
}
render() {
return (
<div>
<input type="checkbox" checked={this.state.agree} onChange={this.setAgree}></input>
< input value={this.state.name} onChange = {this.setName}/>
</div>
)
}
}
export default InputComponents
export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
var title = this.title.value; //added .value
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={input => this.title = input} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};
using uncontrolled fields:
export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
console.log(e.target.neededField.value);
}
render(){
return (
...
<form onSubmit={this.onSubmit} className="form-horizontal">
...
<input type="text" name="neededField" className="form-control" ref={(c) => this.title = c}/>
...
</form>
...
<button type="button" className="btn">Save</button>
...
);
}
};

Why is my onClick being called on render? - React.js

I have a component that I have created:
class Create extends Component {
constructor(props) {
super(props);
}
render() {
var playlistDOM = this.renderPlaylists(this.props.playlists);
return (
<div>
{playlistDOM}
</div>
)
}
activatePlaylist(playlistId) {
debugger;
}
renderPlaylists(playlists) {
return playlists.map(playlist => {
return <div key={playlist.playlist_id} onClick={this.activatePlaylist(playlist.playlist_id)}>{playlist.playlist_name}</div>
});
}
}
function mapStateToProps(state) {
return {
playlists: state.playlists
}
}
export default connect(mapStateToProps)(Create);
When I render this page, activatePlaylist is called for each playlist in my map. If I bind activatePlaylist like:
activatePlaylist.bind(this, playlist.playlist_id)
I can also use an anonymous function:
onClick={() => this.activatePlaylist(playlist.playlist_id)}
then it works as expected. Why does this happen?
You need pass to onClick reference to function, when you do like this activatePlaylist( .. ) you call function and pass to onClick value that returned from activatePlaylist. You can use one of these three options:
1. using .bind
activatePlaylist.bind(this, playlist.playlist_id)
2. using arrow function
onClick={ () => this.activatePlaylist(playlist.playlist_id) }
3. or return function from activatePlaylist
activatePlaylist(playlistId) {
return function () {
// you code
}
}
I know this post is a few years old already, but just to reference the latest React tutorial/documentation about this common mistake (I made it too) from https://reactjs.org/tutorial/tutorial.html:
Note
To save typing and avoid the confusing behavior of this, we will use
the arrow function syntax for event handlers here and further below:
class Square extends React.Component {
render() {
return (
<button className="square" onClick={() => alert('click')}>
{this.props.value}
</button>
);
}
}
Notice how with onClick={() => alert('click')}, we’re passing a
function as the onClick prop. React will only call this function after
a click. Forgetting () => and writing onClick={alert('click')} is a
common mistake, and would fire the alert every time the component
re-renders.
This behaviour was documented when React announced the release of class based components.
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html
Autobinding
React.createClass has a built-in magic feature that bound all methods to this automatically for you. This can be a little confusing for JavaScript developers that are not used to this feature in other classes, or it can be confusing when they move from React to other classes.
Therefore we decided not to have this built-in into React's class model. You can still explicitly prebind methods in your constructor if you want.
import React from 'react';
import { Page ,Navbar, Popup} from 'framework7-react';
class AssignmentDashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
}
onSelectList=(ProjectId)=>{
return(
console.log(ProjectId,"projectid")
)
}
render() {
return (
<li key={index} onClick={()=> this.onSelectList(item.ProjectId)}></li>
)}
The way you passing the method this.activatePlaylist(playlist.playlist_id), will call the method immediately. You should pass the reference of the method to the onClick event. Follow one of the below-mentioned implementation to resolve your problem.
1.
onClick={this.activatePlaylist.bind(this,playlist.playlist_id)}
Here bind property is used to create a reference of the this.activatePlaylist method by passing this context and argument playlist.playlist_id
2.
onClick={ (event) => { this.activatePlaylist.(playlist.playlist_id)}}
This will attach a function to the onClick event which will get triggered on user click action only. When this code exectues the this.activatePlaylist method will be called.

Categories

Resources