Hi I'm new to React and building few things in React and this may seem a very generic question.
I want to show a table on click of button. Below is my code.
import React from 'react';
import { Link }
import Button from 'react-bootstrap/lib/Button';
import Panel from 'react-bootstrap/lib/Panel';
import Grid from 'react-bootstrap/lib/Grid';
import Row from 'react-bootstrap/lib/Row';
import Col from 'react-bootstrap/lib/Col';
import ButtonGroup from 'react-bootstrap/lib/ButtonGroup';
import FormGroup from 'react-bootstrap/lib/FormGroup';
this.state = {
showSubmit: false,
};
submitForm = () => {
window.alert('test');
}
toggleSubmitForm = () => {
this.setState({
showSubmit: !this.state.showSubmit
});
window.alert('test2');
}
export default (props) => {
return (
<AppLayout title="Table Con" activeModules={props.activeModules}>
<Protected>
<div className="container-fluid">
<h4>
Welcome to the page
!
</h4>
</div>
<Button
className="btn btn-secondary"
bsSize="small"
onClick={this.toggleSubmitForm}
>
Show Table
</Button>
{this.state.showSubmit && (
<div className="container-fluid well" id="submitT">
<form onSubmit={this.submitForm}>
<Grid>
<Row>
<Col xs={12}>
<div>
<h3>HERE</h3>
</div>s
<br />
<br />
</Col>
</Row>
</Grid>
<Button type="submit" bsStyle="success" bsSize="large">
Submit
</Button>
</form>
</div>
)}
</Protected>
</AppLayout>
);
};
But when onClick is called, nothing is happening.
I'm not sure where I'm failing.
Also, if i want to call a mongo collection and render the table after I click on Show Table button. What are the changes to be made ?
As #noitse pointed out, you are mixing statefull and stateless component features.
However, React added a new alternative if you want to keep your component as a function, Hooks. Here's what you code will look like as a hook :
import { useState } from 'react'
export default props => {
const[showSubmit, setShowSubmit] = useState(false)
return (
<AppLayout title="Table Con" activeModules={props.activeModules}>
<Protected>
<div className="container-fluid">
<h4>Welcome to the page !</h4>
</div>
<Button className="btn btn-secondary" bsSize="small" onClick={setShowSubmit(true)}>
Show Table
</Button>
{showSubmit && /* Your table*/}
</Protected>
</AppLayout>
);
};
You are combining functional and class component features.
Functional components do not have access to the state unless you are using useState feature (16.3 update). Any "this." is basically undefined in your code.
Rewrite your component like this:
import React, {Component} from 'react' // or PureComponent
// ...other imports
class YourComponent extends Component {
state = {
showSubmit: false
}
submitForm = () => { /* what ever */}
toggleSubmitForm = () => {
this.setState({showSubmit: !this.state.showSubmit})
}
render(){
return(
... your render code
)
}
}
export default YourComponent
Related
I'm new to react and I would like to build a dynamic button, I wrote this code but I don't know How I can pass text, style, and size to this button.
import "./button.css";
import React from "react";
const Button = ({
type,
onClick,
buttonStyle,
buttonSize,
}) => {
return (
<div>
<div>
<button
type={type}
onClick={onClick}
buttonStyle={buttonStyle}
buttonSize={buttonSize}
></button>
</div>
</div>
);
};
export default Button;
In React, html elements does not have buttonStyle and buttonSize attribute. The onClick attribute and the type attribute are valid.
You also need to pass in a props parameter in your Button Const Button(props) and add a style attribute which will contain your style declarations in key:value pair.
Also in order to be dynamic, your button should have a label. you can achieve this by adding props.buttonLabel
Your code should be similar to this code below:
import "./button.css";
import React from "react";
const Button = (props) => {
return(
<div>
<div>
<button
type={props.type}
onClick={props.onClick}
style={props.buttonStyle}
>
{props.buttonLabel}
</button>
</div>
</div>
);
};
export default Button;
I think I found the solution...
import "./button.css";
import React from "react";
const Button = ({ parentClassName, buttonLabel, type, onClick }) => {
return (
<div>
<div>
<button className={parentClassName} type={type} onClick={onClick}>
{buttonLabel}
</button>
</div>
</div>
);
};
export default Button;
ReactDOM.render(
<React.StrictMode>
<Button
type="button"
onClick={() => console.log("you clicked me")}
buttonLabel="Bye Now"
parentClassName="btn btn-secondary"
/>
</React.StrictMode>,
document.getElementById("root")
);
Blockquote
I've only been working with React.js for a month or so and I hope someone can point me towards my errors so I can learn more.
I've created a reusable button component, but during testing, while the button displays correctly and I can change the value correctly - the onClick function is not working. Right now, I am trying to get the button to redirect onClick to the first path.
Below I have added the relevant areas of my code and hope someone can assist.
Display component:
import Sidebar from '../../Components/SideNav/Sidebar'
import GenButton from '../../Components/Buttons/GenButton'
export default function Sales({ authorized }) {
let history = useHistory();
const handleRoute = () =>{
history.push("/")
}
if (!authorized) {
return <Redirect to='/' />
}
return (
<div>
<Sidebar />
<div className='content'>
<h2>Sales Page</h2>
<GenButton
value="Home"
onClick={handleRoute}
/>
</div>
</div>
)
}
GenButton code:
import React from 'react'
import './GenButton.css';
const GenButton = ({value, onClick}) => {
return <button className='btn' onClick={() => onClick}>
{value}
</button>
}
export default GenButton
I need to understand more about why this isn't working, as multiple components I need to create will have between 2-4 buttons that need to route towards other pages or events.
Thank you for your assistance.
Because onClick is a function inside your Gen Button component you need to call it as a function.
import React from 'react'
import './GenButton.css';
const GenButton = ({value, onClick = () => {}}) => {
return <button className='btn' onClick={() => onClick()}>
{value}
</button>
or just
import React from 'react'
import './GenButton.css';
const GenButton = ({value, onClick = () => {}}) => {
return <button className='btn' onClick={onClick}>
{value}
</button>
I added a default value to onClick too incase there isn't one on a particular button.
it's my first application in react and I'm not sure how to disable an imported button.
I have a component button that I import into a parent component
import React, { Component } from "react";
import "../../index.scss";
class Submit extends Component {
render() {
return (
<button className="button"
onClick={() => this.props.onClick()}>
SUBMIT
</button>
);
}
}
export default Submit;
in the component that rendered it is as follows
renderSubmit() {
return (
<Submit
onClick={() => this.submitForm()}
/>
);
}
render() {
return (
<div className="table">
<div className="table-actions">
{this.renderRefresh()}
{this.renderSubmit()}
</div>
</div>
);
}
}
I have tried to set the class to disabled from the original component but it depends on a state property and does not recognize it.
import React, { Component } from "react";
import "../../index.scss";
class Submit extends Component {
render() {
return (
<button className="button"
disabled={this.state.start}
onClick={() => this.props.onClick()}>
SUBMIT
</button>
);
}
}
export default Submit;
How can I condition the disabled state to a state property?
Your Submit button doesn't allow for setting any other props on the underlying button component. It should proxy though any props you want to be externally configured by what is rendering the Submit button. I also suggest explicitly declaring the button type to be "submit", or also exposing that prop out in the component API.
Your proxying of the onClick handler also drops the click event, that should be passed through in case any consuming component care about it.
class Submit extends Component {
render() {
const { disabled, onClick, type = "submit" } = this.props;
return (
<button
className="button"
disabled={disabled}
onClick={onClick}
type={type}
>
SUBMIT
</button>
);
}
}
For such a simple component with no internal logic IMO a functional component is a better option, and I would name it more clearly.
const SubmitButton = ({ disabled, onClick, type = "submit" }) => (
<button
className="button"
disabled={disabled}
onClick={onClick}
type={type}
>
SUBMIT
</button>
);
Now when you are using the submit button from a parent component you can pass in a disabled prop based on any condition you need/require.
render() {
const { submitDisabled } = this.state;
return (
<div className="table">
<div className="table-actions">
{this.renderRefresh()}
<SubmitButton
disabled={submitDisabled} // <-- pass disabled value
onClick={this.submitForm} // <-- attach click handler
type="button" // <-- so we don't accidentally take default form action
/>
</div>
</div>
);
}
}
How you compute/set this.state.submitDisabled is up to you. Maybe it is disabled when the form is being submitted, for example.
submitForm = () => {
this.setState({ submitDisabled: true });
...
};
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' />
I have created a react component and I'm reusing it in other components.
<SC_Button label = "English" btnStyle = "sc-btn-default--sinhala mb-2" onClick={this.handleClick}/>
But function defined at onClick does not execute because it's with props passed to the component. I guess react reads onClick as a prop as well. I'm quite new to react.
Below way works. But I don't want to wrap my react component with an extra div due to a styling issue.
<div onClick={this.handleClick} >
<SC_Button label = "English" btnStyle = "sc-btn-default--sinhala mb-2"/>
</div>
Is there any way to use props along with other attributes in react component definitions ?
Edit :
Parent Component
import React from 'react';
import { withRouter } from "react-router-dom";
import SC_Button from '../components/button';
class Home extends React.Component {
handleClick = () => {
this.props.history.push('/page2');
}
render() {
return (
<div className="container-fluid">
<div className="row sc-overlay sc-overlay-main">
<div className="col-md-12 col-xl-5 offset-xl-1">
<span className = "sc-overlay-main__left">
<span className = "sc-main-image">
<img src={require('../assets/dialog_logo.png')} />
</span>
<h1 className="mt-4">Welcome to MyDialog</h1>
</span>
</div>
<div className="col-md-12 col-xl-5">
<div className="row sc-overlay-main__right">
<label>Choose your preferred language</label>
<SC_Button label = "සිංහල" btnStyle = "sc-btn-default--sinhala mb-2" onClick={this.handleClick}/>
<SC_Button label = "தமிழ்" btnStyle = "sc-btn-default--tamil mb-2" />
<SC_Button label = "English" btnStyle = "sc-btn-default--english mb-2" />
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Home);
SC_Button Component
import React from 'react';
import { withRouter } from "react-router-dom";
class SC_Button extends React.Component{
constructor(props) {
super(props);
}
render() {
return (
<button type="button" className={`sc-btn-default ${ this.props.btnStyle }`}>{this.props.label}</button>
);
}
}
export default withRouter(SC_Button);
Your <SC_Button /> component, or any custom component you make, doesn't automatically implement an event handler. You're essentially just giving it yet another prop, called onClick, that it just throws away. You have to use the callback you're passing it in the DOM elements it returns:
SC_Button.js
import React from 'react';
import { withRouter } from "react-router-dom";
class SC_Button extends React.Component{
constructor(props) {
super(props);
}
render() {
return (
<button
type="button"
className={`sc-btn-default ${ this.props.btnStyle }`}
onClick={this.props.handleClick}
>
{this.props.label}
</button>
);
}
}
export default withRouter(SC_Button);
There is no need to define a handleClick function in the component, since you will be passing it as a prop every time you instantiate one. This allows different instances to have different behaviors.