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 });
...
};
Related
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.
I have a Form that has a group of checkboxes, Radio buttons and a Button.
Each time I update the value of a checkbox or radio button it dispatches an event that updates my state. I can see this state by clicking my button component: <Button context={ExampleContext} />
However, I can't seem to access my state the same way in the parent container by adding the same code snippets as it just returns undefined, this is the same logic that I have inside my Button component, so I'm not sure why it's not working.
I'm clearly doing something wrong, but I'm not sure what. How do I go about accessing my state from within the parent container?
I also have a working example here: https://codesandbox.io/s/elegant-minsky-0i4yx
Thanks for any help!
// This doesn't seem to work
const { state } = useContext(ExampleContext);
<button onClick={() => console.log(state)}>See State</button>
import React from "react";
import Checkbox from "./Checkbox";
import Radio from "./Radio";
import Button from "./Button";
import { ExampleProvider, ExampleContext } from "./ExampleContext";
const { useContext } = React;
const Form = () => {
const { state } = useContext(ExampleContext);
return (
<ExampleProvider>
<Checkbox context={ExampleContext} />
<Radio context={ExampleContext} />
<Button context={ExampleContext} />
<button onClick={() => console.log(state)}>See State</button>
</ExampleProvider>
);
};
export default Form;
Your useContext hook is not inside the ExampleProvider context Provider.
You can fix it like this
const Form = () => {
const { state } = useContext(ExampleContext);
return (
<>
<Checkbox context={ExampleContext} />
<Radio context={ExampleContext} />
<Button context={ExampleContext} />
<button onClick={() => console.log(state)}>See State</button>
</>
);
};
const FormWrapper = () => {
return (
<ExampleProvider>
<Form />
</ExampleProvider>
);
};
export default FormWrapper;
Look at this blogpost if you need to learn about the best way to handle the state management with React context API.
I have three components: MyDashboard, MyContent, MyForm.
The MyDashboard component starts off by rendering the MyContent component as a child. I have a button within the MyContent component which when clicked should swap out the component with the MyForm component.
Clicking the button flashes the MyForm component on the first click, then goes straight back to the MyContent component. After the second click however the MyForm component is rendered and stays rendered.
MyDashboard:
function MyDashboard(props) {
const [viewForm, setViewForm] = useState(false); // Don't show the form initially
const handleClick = () => {
setViewForm(!viewForm);
};
return (
<div>
{(() => {
if (viewForm) { // conditionally render the form or the content
return <MyForm {...props} />;
} else {
return (
<MyContent
{...props}
setViewForm={handleClick}
viewForm={viewForm}
/>
);
}
})()}
</div>
);
}
MyContent:
function MyContent(props) {
return (
<p>
<a href="#" onClick={props.setViewForm}> // need to click this twice to render the form.
Show the form
</a>
</p>
);
}
export default MyContent;
MyForm:
function MyForm({ props, location }) {
// form setup
return (
<div>
<Row>
<Form>
//... the form
</form>
</Row>
</div>
);
}
export default MyForm;
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
I have a stateless component and i want to be able to click on the image and redirect it to a new page.
The issue that i am having is that i cannot get onClick to work correctly.
I was trying to write a function within the onClick = {this.ProjectSelected} but this will not work.
Do i have to pass a function (onClick) from the parent to child component? If so how do i do that?
I am able to log the project id to the console.
Thanks for the help.
const projectListTemplates = (props) => {
const { classes } = props;
return (
<div>
<div className={classes.root}>
<GridList className={classes.gridList}>
<GridListTile key="Subheader" cols={2} style={{ height: 'auto' }}>
<Subheader component="div">Projects</Subheader>
</GridListTile>
{props.data.map(item => (
<GridListTile key={item.image}>
<img src="./images/Project/1.jpg" alt={item.title} />
<GridListTileBar
title={item.title}
subtitle={<span> {item.name}</span>}
onClick={()=>console.log(`this project was clicked ${item.id}`)}
>
</GridListTileBar>
/>
<ProgressBar now={60} />
</GridListTile>
))}
</GridList>
</div>
</div>
);
In stateless component we are not defining any local property like state or methods. We have only props and rendering data based on props. We have only props events to trigger. So we have to pass a event function from parent component in order to handle click event. If you want to keep click event locally, convert component to stateful (Class).
Stateless
const ProjectListComponent = (props) => {
const { onClick } = props
return (
<button onClick={onClick}>Click me</button>
)
}
class AppComponent extends Component {
handleClick() {
console.log('clicked')
}
render() {
return (
<ProjectListComponent onClick={this.handleClick} />
)
}
}
Stateful
class ProjectListComponent extends Component {
handleClick() {
console.log('clicked')
}
render() {
return (
<button onClick={this.handleClick}>Click me</button>
)
}
}