How to pass value of button to the function in react - reactjs

I want that on clicking the button X its value X pass to the result function(same with O) where I can store it in a variable. I don't know how to pass this value on calling result and access it there. I tried to find many answers but none worked.
I'm absolutely new to react. Please help!! Thanks!!
This is code snippet
import React, { Component } from 'react';
import './App.css';
import { Link } from 'react-router-dom';
class App extends Component {
render() {
return (
<div>
<h1 align="center">Welcome to TicTacToe</h1>
<br></br><br></br><br></br><br></br>
<div class="front">
Choose your sign !!
<CheckBox type='submit' value='X' id='x' onSubmit={'how to pass value'}/>
<CheckBox type='submit' value='O' id='o' onSubmit={'how to pass value'}/>
</div>
<br></br>
<Link to= "game"><p class="wrap"><button class="button">GO</button></p></Link>
{this.props.children}
</div>
);
}
}
class CheckBox extends Component{
result(i){
//what to access value
}
render(){
return (
<div className={'check-field'}>
<button type={this.props.type} value={this.props.value} name={this.props.name} id={this.props.id}>{this.props.value}</button>
</div>
);
}
}
export default App;

I'm not sure if I understand your problem properly, but to get a value from a child input component (input/button/textarea) in its parent, just pass a prop with a function which will be called in the child on any onClick/onChange callback function. Here's a little example:
class App extends React.Component {
onSubmit(value) {
// I have the button value here!
console.log(value);
}
render() {
return (
<div>
<Button value="X" onSubmit={this.onSubmit} />
<Button value="O" onSubmit={this.onSubmit} />
</div>
)
}
}
class Button extends React.Component {
onClick(event) {
const value = event.target.value;
this.props.onSubmit(value);
}
render() {
return (
<button value={this.props.value} onClick={e => this.onClick(e)}>
{this.props.value}
</button>
);
}
}
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" />
I hope this solves your problem!

You can store for each checkbox value in state of App. Then, when checkbox is subimtted value it will call handleSubmit and event parameter e holds value and id of checkbox. In your case you can examine if it's X or Y and setState accordingly. This will re-render checkboxes who will via props get proper values.
import React, { Component } from 'react';
import './App.css';
import { Link } from 'react-router-dom';
class App extends Component {
state = {
X : false,
Y : false
}
handleSubmit = (e) => {
if(e.target.id === 'x') {
this.setState({X:true});
} else {
this.setState({Y:true});
}
}
render() {
const { X,Y } = this.state;
return (
<div>
<h1 align="center">Welcome to TicTacToe</h1>
<br></br><br></br><br></br><br></br>
<div class="front">
Choose your sign !!
<CheckBox type='submit' value={X} id='x' onSubmit={this.handleSubmit}/>
<CheckBox type='submit' value={Y} id='o' onSubmit={this.handleSubmit}/>
</div>
<br></br>
<Link to= "game"><p class="wrap"><button class="button">GO</button></p></Link>
{this.props.children}
</div>
);
}
}
class CheckBox extends Component{
render(){
const {value, type, name, id} = this.props;
return (
<div className={'check-field'}>
<button type={type} value={value} name={name} id={id}>{value}</button>
</div>
);
}
}
export default App;

Related

React render button 'x' of times

I have a switch button that I want to copy ten times but when I copy the button to new div it does not let me click on second button onwards, I can change state of one first button only. Here is my code
class App extends Component {
handleSwitch = e => console.log(e.target.checked);
render() {
return (
<div>
<div>
<p className="title">source</p>
<label className="label">Button</label>2
<SwitchButton
onChange={this.handleSwitch}
title="SwitchButton"
data-name="vd"
/>
</div>
<div>
<label className="label">Button2</label>
<SwitchButton
onChange={this.handleSwitch}
title="SwitchButton2"
data-name="vd1"
/>
</div>
</div>
);
}
}
here is my live demo : https://stackblitz.com/edit/react-ts-9n4lwa?file=index.tsx
You should set a unique switchButtonID in each SwitchButton
import React, { Component } from 'react';
import { render } from 'react-dom';
import SwitchButton from './Hello';
import './style.scss';
class App extends Component {
handleSwitch = e => console.log(e.target.checked);
render() {
return (
<div>
<div>
<p className="title">Precursor source</p>
<label className="label">Ch1_PulsingValveActivationlnSw</label>
<SwitchButton
switchButtonID={1}
onChange={this.handleSwitch}
title="SwitchButton"
data-name="vd"
/>
</div>
<div>
<label className="label">Ch1_PulsingValveActivationlnSw</label>
<SwitchButton
switchButtonID={2}
onChange={this.handleSwitch}
title="SwitchButton2"
data-name="vd1"
/>
</div>
</div>
);
}
}
render(<App />, document.getElementById('root'));

How to set state properly in react js

I have 2 react components -
import React, {Component} from 'react'
import './App.css';
import ContactCard from './components/ContactCard'
class App extends Component {
render() {
return (
<div className="App-header">
<ContactCard name="hi 1" age={36} email="hu#yahoo.com"/>
<ContactCard name="hi 2" age={67} email="hi#yahoo.com"/>
<ContactCard name="hi 2" age={42} email="he#yahoo.com"/>
</div>
);
}
}
export default App;
import React, { Component } from "react";
class ContactCard extends Component {
state = {
showAge: false,
};
setAge = () => {
this.setState({
showAge: !this.state.showAge,
});
};
render() {
return (
<div className="contactCard">
<div className="userDetails">
<h2>Name: {this.props.name}</h2>
<p>Email: {this.props.email}</p>
<button onClick={this.state.setAge}>Show Age</button>
{this.state.showAge && <p>Age: {this.props.age}</p>}
</div>
</div>
);
}
}
export default ContactCard;
Toggle button is not working. i have set the state before render method. its not mandatory to set the state in the constructor.
Now the error is gone but still toggle button not working.
Whats going wrong?
You are setting state the wrong way. It should be:
setAge = () => {
this.setState({
showAge: !this.state.showAge
});
};
Edit
In order to make your app work as expected, you also have to set the click handler properly:
<button onClick={this.setAge}>Show Age</button>
You have to update your code its this.setAge not this.state.setAge
render() {
return (
<div className="contactCard">
<div className="userDetails">
<h2>Name: {this.props.name}</h2>
<p>Email: {this.props.email}</p>
<button onClick={this.setAge}>Show Age</button>
{this.state.showAge && <p>Age: {this.props.age}</p>}
</div>
</div>
);
}

Rendering a Bootstrap Component Using JSX

Editing for clarity: I cannot figure out how to dynamically create Boostrap Components using JSX in a react app. End goal is to get the new button in the "newBtnSpace" div when the first button is clicked. I have tried using show.hide methods, but those need to be hard coded. Trying to create buttons based off an array. code:
./components/newBSBtnSpaceFunc.js
import React, { Component } from 'react'
import { Button } from 'reactstrap'
export default function NewBSBtnFunc() {
let BtnArray = ["red", "blue", "green"].map((btn) => {
return React.createElement(
Button,
{variant: 'primary'},
'New Button',
{id: "newBtn"},
btn
)
}
./components/BSBtn.js
import React, { Component } from 'react'
import { Button } from 'reactstrap'
import NewBSBtnFunc from "./NewBSBtnFunc"
export default class BSBtn extends Component {
render() {
return (
<div>
<Button onClick={NewBSBtnFunc}>Click Me</Button>
<div id="newBtnSpace"></div>
</div>
)
}
}
App.js
import React from 'react';
import 'bootstrap/dist/css/bootstrap.min.css';
import BSBtn from "./components/BSBtn"
function App() {
return (
<div>
<BSBtn></BSBtn>
</div>
);
}
export default App;
github link: https://github.com/mollygilbert389/testingBootstrapBtn
You can conditionally show the new button by setting a state item (in this case showNewButton) to true in the onClick of the original button.
render() {
return (
<div>
<Button onClick={() => this.setState({ showNewButton: true }))}>Click Me</Button>
<div id="newBtnSpace">{ this.state.showNewButton && <Button variant="primary" id="newBtn">New Button</Button> }</div>
</div>
)
}
PS you've already successfully worked out how to create Bootstrap buttons in jsx:
<Button onClick={NewBSBtnFunc}>Click Me</Button>
onClick does not expect a return value so returning the new button won't do anything.
The way you have things organized makes it very difficult since you can't return anything from the function, and you can't modify state from outside the class. I would suggest moving your click handler into the component and using to to modify a state value that will show the second button.
Here is my suggestion:
import React, { Component } from 'react'
import { Button } from 'reactstrap'
export default class BSBtn extends Component {
state = {show: false}
handleClick = () => {
this.setState({ show: !this.state.show })
}
render() {
return (
<div>
<Button onClick={this.handleClick}>Click Me</Button>
<div id="newBtnSpace">
{this.state.show ?
<Button variant="primary" id="newBtn">New Button</Button>
: null}
</div>
</div>
)
}
}
Updated solution to your updated question:
class BSBtn extends React.Component {
state = {
show: false,
buttons: []
}
handleClick = () => {
this.setState({ show: !this.state.show })
}
handleAdd = () => {
this.setState({ buttons: [...this.state.buttons, (this.state.buttons.length + 1)] })
}
render() {
return (
<div>
<h3>Option 1</h3>
<button onClick={this.handleClick}>Click Me</button>
<div id="newBtnSpace">
{this.state.show ? [1,2,3].map((value) => (
<div>
<button>Button {value}</button>
</div>
))
: null}
</div>
<hr/>
<div style={{ marginTop: '30px' }}>
<h3>Option 2</h3>
<button onClick={this.handleAdd}>Click Me</button>
{this.state.buttons.map((value) => (
<div>
<button>Button {value}</button>
</div>
))}
</div>
</div>
)
}
}
ReactDOM.render(<BSBtn />, document.getElementById('root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id='root' />

Pass map's argument to function in ReactJS

I am trying to make a todoList by ReactJS. I want to delete an item by its id, but when I console.log(id), it returns undefined. Here is my code
App.js:
import React, { Component } from 'react';
import './App.css';
import Header from './Components/header';
import InputTodo from './Components/todoInput';
class App extends Component {
constructor(props){
super(props);
this.state={
todos:[
{id:0,text:'Make dinner'},
{id:1,text:'Fold the laundary'},
{id:2,text:'Do homework'}
]
}
}
addHere=(text)=>{
this.setState({
todos:this.state.todos.concat([text])
})
}
removeHere=(id)=>{
console.log(id);
// let arr=this.state.todos;
// let index=arr.findIndex((x)=>x.id===id);
// console.log(index);
}
render() {
return (
<div className='todo-wrapper'>
<Header/>
<InputTodo todoText='Type Here...' addTodo={this.addHere}/>
<div>
{this.state.todos.map((value,key)=>{
return (
<div className='row myList' key={key}>
<p className='col-xs-10'> {value.text}-{value.id} </p>
<button className='btn btn-danger pull-right col-xs-2' onClick={this.removeHere(value.id)}>Delete</button>
</div>
)})}
</div>
</div>
);
}
}
export default App;
The following is InputTodo.js:
import React, {Component} from 'react';
import '../App.css';
export default class InputTodo extends Component{
constructor(props){
super(props);
this.state={
todoInput:{
id:2,
text:''
}
}
}
handleSubmit=(e)=>{
if(this.refs.title.value===''){
alert('You must input something');
}
else{
this.state.todoInput={
id:this.state.todoInput.id+1,
text:this.refs.title.value
};
this.setState(this.state);
this.props.addTodo(this.state.todoInput);
this.refs.title.value='';
}
e.preventDefault();
}
render(){
return(
<form className='input-group' onSubmit={this.handleSubmit}>
<input type='text' ref="title" className='form-control'placeholder={this.props.todoText}/>
<span className='input-group-btn'>
<input type='submit' value='Submit' className='btn btn-primary' />
</span>
</form>
);
}
}
While FuzzyTree's answer will work, a cleaner approach would be extracting the todo item's JSX into its own component. This would have the added benefit of not creating a new function for the button's onClick prop every time App's render function gets called.
The component might look like this:
// TodoItem
class TodoItem extends Component {
handleRemove = () => this.props.onRemove(this.props.id)
render() {
return (
<div className='row myList'>
<p className='col-xs-10'> {this.props.text}-{this.props.id} </p>
<button className='btn btn-danger pull-right col-xs-2' onClick={this.handleRemove}> Delete </button>
</div>
)
}
}
// App render
render() {
return (
<div className='todo-wrapper'>
<Header/>
<InputTodo todoText='Type Here...' addTodo={this.addHere}/>
<div>
{this.state.todos.map(({ id, text }, key) =>
<TodoItem key={key} id={id} text={text} onRemove={this.removeHere} />
)}
</div>
</div>
);
}

Passing state in React from two different components

I have a TopNab bar (component), which contains a SearchBar component. My Main component is rendering out TopNav, the main container component (Profile), and the Footer component. I want my SearchBar component to pass its state to the main container component so that the Profile component can use it.
What I am trying to build:
A user types a name into search bar and submits.
The profile matching the user name is displayed in the main container component.
Right now I have a component that can render out user profiles. I also have a component thats state updates to the user submitted value. What I need to do is pass this user submitted value to my profile component in order to render out the correct profile.
Is this possible or do I need to rebuild my components so the search is included in the Profile component?
SearchBar
import React, { Component, PropTypes } from 'react';
import Profile from './Profile';
class SearchBar extends Component {
constructor(props){
super(props)
this.state = {
name: ''
}
}
handleChange(e) {
this.setState({
name: e.target.value
});
}
handleSubmit(e) {
e.preventDefault();
console.log("searching for NAME " + this.state.name);
let profileName = this.state.name;
//PASS STATE TO PROFILE COMPONENT
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit.bind(this)}>
ARMORY BETA
<input type="text" placeholder="Enter Name"
name="name"
value={this.state.name}
onChange={this.handleChange.bind(this)} />
<button className="btn btn-success" type="submit">Search</button>
</form>
</div>
)
}
}
export default SearchBar;
Profile
import React, { Component, PropTypes } from 'react';
import SearchBar from './SearchBar';
import ProfileContainer from '../containers/ProfileContainer';
class Profile extends Component {
render() {
return (
<div className="cols2">
<div>[IMG]</div>
<div>
<ProfileContainer name={this.props.name}/>
</div>
</div>
)
}
}
Profile.PropTypes = {
name: PropTypes.string
}
Profile.defaultProps = {
name: ''
}
export default Profile;
Main
import React, { Component } from 'react';
import TopNav from './TopNav';
import Footer from './Footer';
import Profile from './Profile';
class Main extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
//TopNav calls SearchBar
<TopNav />
</div>
<div className="row">
<Profile />
</div>
<div className="row">
<Footer />
</div>
</div>
)
}
}
export default Main;
In Main, you should add a prop to <TopNav /> that points to a handler method that will propagate the profileName state change back to Main. This, in turn, will cause Profile to be re-rendered. The handler method takes one argument profileName and is called from the handleSubmit method in TopNav. Here's the code:
SearchBar
class SearchBar extends Component {
. . .
handleSubmit(e) {
e.preventDefault();
console.log("searching for NAME " + this.state.name);
let profileName = this.state.name;
this.props.handleProfileChange(profileName);
}
. . .
}
SearchBar.propTypes = {
handleProfileChange: React.PropTypes.func.isRequired,
}
Main
class Main extends Component {
constructor(props) {
super(props);
this.state = { profileName: '' }
handleProfileChange = this.handleProfileChange.bind(this);
}
handleProfileChange(profileName) {
// This state change will force Profile component to be re-rendered
this.setState( { profileName });
}
render() {
return (
<div className="container-fluid">
<div className="row">
//TopNav calls SearchBar
<TopNav handleProfileChange={this.handleProfileChange} />
</div>
<div className="row">
<Profile profileName={this.state.profileName} />
</div>
<div className="row">
<Footer />
</div>
</div>
)
}
You'll need to expose a property on SearchBar that accepts a callback that will be called to indicate to its parent that the form was submitted (e.g. onSubmit)...
handleSubmit(e) {
e.preventDefault();
console.log("searching for NAME " + this.state.name);
let profileName = this.state.name;
//PASS STATE TO PROFILE COMPONENT
this.props.onSubmit(yourFormData);
}
...TopNav won't handle onSubmit itself, but just pass it on up to its own parent (perhaps renaming to "onSearchBarSubmit" along the way to make the name clearer from the perspective of TopNav's parent):
class TopNav extends Component {
render() {
return (
<div className="container-fluid">
<SearchBar onSubmit={this.props.onSearchBarSubmit}
</div>
);
}
}
class Main extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
<TopNav onSearchBarSubmit={ (criteria) => this.searchForStuff(criteria) } />
</div>
<div className="row">
<Profile data={this.state.stuffYouGotBackFromSearch} />
</div>
<div className="row">
<Footer />
</div>
</div>
)
}
}
...OR, in some cases, it can be desirable to un-nest the components, allowing SearchBar as one of TopNav's props.children. This allows you to handle onSubmit directly within Main, and pass anything it receives onto Profile:
class Main extends Component {
render() {
return (
<div className="container-fluid">
<div className="row">
//TopNav calls SearchBar
<TopNav>
<SearchBar onSubmit={ (criteria) => this.searchForStuff(criteria) } />
</TopNav>
</div>
<div className="row">
<Profile data={this.state.stuffYouGotBackFromSearch} />
</div>
<div className="row">
<Footer />
</div>
</div>
)
}
}
...a side-benefit of un-nesting is that it would allow you to use TopNav and Searchbar independently.

Resources