Quick way to reference an element in a React component? - javascript

I have a component that has an input field and button. I want to add an onclick handler on the button that uses the value of the input. I can do this with querySelector, or getElementbyId or having a parent form element, or changing the input to a component. But what I want to know is if there's a direct and easy way just to refence the element.
import React from "react";
export default class UserInput extends React.Component{
constructor(props){
super(props);
this.doStuff = this.doStuff.bind(this);
}
doStuff(){
const inputValue = document.getElementById('new-task').value // I want to replace this
// do stuff
}
render(){
return(
<div id="user-input">
<input type="text" id="new-task"></input>
<button type="button" onClick={this.doStuff}>Do Stuff!</button>
</div>
)
}
}

I think you can do it this way. Just give it a try.
import React from "react";
export default class UserInput extends React.Component{
constructor(props){
super(props);
this.textInput = React.createRef();
this.doStuff = this.doStuff.bind(this);
}
doStuff(){
const inputValue = this.textInput
}
render(){
return(
<div id="user-input">
<input type="text" id="new-task" ref={this.textInput}></input>
<button type="button" onClick={this.doStuff}>Do Stuff!</button>
</div>
)
}
}

Related

How to update react component state from one component to another, and call any functions from any component

I am very new to react, when I put everything in one place, it works fine. But when I split it into components, everything went wrong.
I have two files App.js and Activity1.js
Activity1.js contains an input with an event handler attached to it. This input is simply wrapped inside a div.
The input was initially in App.js but I extracted it to Activity.js.
The input has a sibling, a div where I echo whatever the user types in the input, by updating the props state. How can I update the state. Your time and interest is appreciated.
Here's my code:
App.js
import './App.css';
import React from 'react';
import Activity1 from './f/Activity1';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {value:15};
}
checkInput = e => {
this.setState({value: e.target.value});
}
render(){
return (
<div className="p-2">
<div>
<Activity1 />
</div>
</div>
)
}
}
export default App;
Here's Activity1.js
import React from "react";
class Activity1 extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<div>Enter Number</div>
<input className="form-control" onChange={this.checkInput} />
<div className="p-2 mt-3">{this.state.value}</div>
</div>
)
}
}
export default Activity1;
Hope this solves the problem.
app.js
...
<Activity1 checkInput = {this.checkInput} inputValue = {this.state.value}/>
...
Activity1.js
...
render() {
const {checkInput, inputValue} = this.props;
...
<input className = "form-control" onChange = {checkInput} />
<div className = "p-2 mt-3"> {inputValue} </div>
You can pass a function as a prop to the other component.
<div>
<Activity1 checkInput={this.checkInput} inputValue = {this.state.value}/>
</div>
In your Activity1 component,
const {checkInput, inputValue} = this.props;
onChangeEventHandler= () => {
checkInput();
}
and
<input className = "form-control" onChange = ={this.onChangeEventHandler} />
<div className = "p-2 mt-3"> {this.inputValue} </div>
https://dev.to/vadims4/passing-down-functions-in-react-4618
You can use a Callback function
<Activity checkInput = {this.checkInput} inputValue = {this.checkInput.bind(this)}/>

ReactJs: How to add/append a component on click of button

Say <componentX \> when onClick of "create box" button, the componentX should append inside of box-container. If i click create box 3 times, then three componentX should append inside box-container (It's not that simply keeping the component then hide and show when click of create box). What are all the ways to achieve this in ReactJS.
import ComponentX from './ComponentX.jsx';
class App extends React.Component{
constructor(){
super();
this.state = {
}
}
render(){
let board = Box;
return(
<div>
<a onClick={}>Create Box</a>
<div className="box-container"></div>
</div>
);
}
}
export default App;
Try something like this:
import ComponentX from './ComponentX.jsx';
class App extends React.Component{
constructor(){
super();
this.state = {
children: [];
}
}
appendChild(){
this.setState({
children: [
...children,
<componentX \>
]
});
}
render(){
let board = Box;
return(
<div>
<a onClick={() => this.appendChild()}>Create Box</a>
<div className="box-container">
{this.state.children.map(child => child)}
</div>
</div>
);
}
}
export default App;
You can conditionally render by using component state like this:
import ComponentX from './ComponentX.jsx';
class App extends React.Component{
constructor(){
super();
this.state = {
showComp = false;
}
}
handleClick = () => {
this.setState({
showComp: true,
})
}
render(){
let board = Box;
const { showComp } = this.state;
return(
<div>
<a onClick={this.handleClick}>Create Box</a>
<div className="box-container">
{showComp && <ComponentX />
</div>
</div>
);
}
}
export default App;

Typechecking in React

I have a multilevel hierarchy class A-> class B-> class C through which I have to pass numbers.
The parent class is the App class like this-
import propTypes from 'prop-types';
class App extends React.Component{
constructor(props){
super(props);
this.state={
text:0,
isClicked:false
}
this.display=this.display.bind(this);
}
display(){
var num=document.getElementById('number').value;
var text=parseInt(num);
this.setState({
isClicked:true,
text:text
})
}
render(){
return(
<div className="row">
<div className="col-md-6">
<input type="text" placeholder="Enter name" value={this.state.label}/>
<input type="text" type='number' id='number'/>
<button onClick={this.display}>Click here</button>
</div>
<div className="col-md-6">
<Display click={this.state.isClicked} data={this.state.text}/>
</div>
</div>
)
}
}
App.propTypes={
text:propTypes.number,
num:propTypes.number,
data:propTypes.number
}
The Display class is the child class of App class and it is like this
import propTypes from 'prop-types';
class Display extends React.Component{
constructor(props){
super(props);
this.state={
num:this.props.data,//This value of number is coming as undefined
value:0
}
}
render(){
//console.log(this.state.data);
if(this.props.isClicked===true){
return(<DonutChart data={this.state.num}/>)
}else{
return(<DonutChart data={this.state.value}/>)
}
}
}
Display.propTypes={
data:propTypes.number,
num:propTypes.number
}
And the child class of Display class is DonutChart class which is like this
import propTypes from 'prop-types';
const DonutChart= React.createClass({
propTypes:{
data:React.PropTypes.number,
},
getDefaultProps(){
return{
value:0,
size:116
}
},
render(){
//console.log(this.props.data); This comes as 0 on the console
return(
<svg height={this.props.size} width={this.props.size}>
</svg>
)
}
})
I get this error as 'expected number but got a string' error in React. And the value of data is not getting passed to the child classes. What is the problem here?
You want this.props.data.size and your propTypes declaration in Donutchart is also erroneous also in your parent component you are only passing data instead of this.state.data. For your Donut chart, you could use a stateless functional component because you container component can handle state and props, Your chart's only job is to display info.

How can I use "Enter" button to setState to my component

I'm a real beginner with ReactJs Es6, I'm trying to setState to my component when I hit the "Enter" Button, I have tried some of the answers here, like this one, https://stackoverflow.com/a/34634290/8301413, but it hasn't worked the way I want to.
What I have so far is when I enter a text on my input box, the <h1> changes it's state and displays the state with every character input. What I want to happen is, I input my text first, then when I hit enter, that's the only time the state updates and displays the text from the input box.
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
export class App extends Component {
constructor(props) {
super(props);
this.state = { userInput: '' };
this.handleUserInput = this.handleUserInput.bind(this);
}
handleUserInput(e) {
this.setState({userInput: e.target.value});
}
render() {
return (
<div>
<input
type="text"
value={this.state.userInput}
onChange={this.handleUserInput}
/>
<h1>{this.state.userInput}</h1>
</div>
);
}
}
export default App;
To achieve that behaviour use uncontrolled component, means don't use the value property of input element. Instead of using onChange event use onKeyDown and check the keyCode, update the state only when user press the enter key.
Check this working snippet:
class App extends React.Component {
constructor(props) {
super(props);
this.state = { userInput: '' };
this.handleUserInput = this.handleUserInput.bind(this);
}
handleUserInput(e) {
if(e.keyCode == 13)
this.setState({userInput: e.target.value});
}
render() {
return (
<div>
<input
type="text"
onKeyDown={this.handleUserInput}
/>
<h1>{this.state.userInput}</h1>
</div>
);
}
}
ReactDOM.render(<App/>, document.getElementById('app'))
<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='app'//>
#Mayank Shukla answer may be right, however it changes it to uncontrolled component.
Demo
You just need to add on more event onKeyPress which waits for "Enter" key.
class App extends React.Component {
constructor(props) {
super(props);
this.state = { userInput: '', output: '' };
this.handleUserInput = this.handleUserInput.bind(this);
this.handleChange = this.handleChange.bind(this);
}
handleUserInput(e) {
if (e.key === 'Enter') {
this.setState({output: e.target.value});
}
}
handleChange(e) {
this.setState({userInput: e.target.value});
}
render() {
return (
<div>
<input
type="text"
value={this.state.userInput}
onKeyPress={this.handleUserInput} // Only for "Enter" purpose
onChange={this.handleChange}
/>
<h1>{this.state.output}</h1>
</div>
);
}
}
This way you still keep the component controlled.
Example of Controlled Component objective

How to render component again at the top level with the new props in React 0.14

In the new React.js 0.14 setProps method was deprecated form React.Component. According to documentation, now we should render component again with new props(using ReactDOM.render())
The question is how can I do this? Let's look at an example.
AddTaskForm.js
import React from 'react';
class AddTaskForm extends React.Component
{
onClick() {
this.setProps({
isVisible: false
});
}
render() {
return (
<form role="form">
<div className="row" className={ this.props.isVisible ? 'show' : 'hidden' }>
<input className="form-control" type="text" />
</div>
<button type="button" className="btn" onClick={this.onClick.bind(this)}>Add task</button>
</form>
);
}
}
export default AddTaskForm;
Todo.js
var React = require('react');
var ReactDOM = require('react-dom');
var AddTaskForm = require('./AddTaskForm');
class Todo extends React.Component
{
render() {
return (
<div>
<AddTaskForm isVisible="false"></AddTaskForm>
</div>
);
}
}
ReactDOM.render(<Todo />, document.getElementById('app'));
Btw. I am using ES6 stage 0, if you find yourself confused with syntax
Ok, I can't call setProps, i had to rerender AddTaskForm component in Todo.js. How can I do this in this case? I've read this article form react's blog but wrapper don't really help me.
You should not use setProps at all. Properties in React must be immutable data, so you can't change them. Looks like isVisible prop is really part of component state, because depends on it component decides to show or not to show itself. The best choice for such situations when after some change of data you need to update component is state. I would recommend to read this doc about state and what should and should not go to state
From your example:
<div>
<AddTaskForm isVisible="false"></AddTaskForm>
</div>
.. how do you know should AddTaskForm be visible? For now it's hardcoded. I suggest doing something like that:
render () {
let shouldFormBeVisible = ...// somehow get to know should it be visible or not
return (
<div>
shouldFormBeVisible ? <AddTaskForm /> : null
</div>
)
}
Here is a big advantage: you even don't need to render AddTaskForm and if isVisible is false then hide it. You don't render component if it isn't needed.
isVisible is a piece of mutable state, so it needs to be stored in state somewhere.
One way is to put it on the AddTaskForm:
import React from 'react';
class AddTaskForm extends React.Component
{
constructor(props, context) {
super(props, context);
this.state = { isVisible: true};
}
onClick() {
this.setState({
isVisible: false
});
}
render() {
return (
<form role="form">
<div className="row" className={ this.state.isVisible ? 'show' : 'hidden' }>
<input className="form-control" type="text" />
</div>
<button type="button" className="btn" onClick={this.onClick.bind(this)}>Add task</button>
</form>
);
}
}
export default AddTaskForm;
Todo.js
var React = require('react');
var ReactDOM = require('react-dom');
var AddTaskForm = require('./AddTaskForm');
class Todo extends React.Component
{
render() {
return (
<div>
<AddTaskForm />
</div>
);
}
}
ReactDOM.render(<Todo />, document.getElementById('app'));
Another way is to store it on the Todo component, but I think you have enough to get started.

Categories

Resources