classes vs styles for CSS className in Reactjs - javascript

In the below code, why does a call to the classes object work? It seems like the call should be to the styles object defined as a const up top.
For example, in this demo:
className={classes.button}
works as written. But it seems like it should be
className={styles.button}
Is there any actual classes object defined anywhere? If so, where is it defined? The markup implies a this.props.classes object. But there are no props passed to <Demo /> when called in index.js.
What's going on here?
https://codesandbox.io/s/qxv466wlq
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Button from '#material-ui/core/Button';
const styles = theme => ({
button: {
margin: theme.spacing.unit,
},
input: {
display: 'none',
},
});
function OutlinedButtons(props) {
const { classes } = props;
return (
<div>
<Button variant="outlined" className={classes.button}>
Default
</Button>
<Button variant="outlined" color="primary" className={classes.button}>
Primary
</Button>
<Button variant="outlined" color="secondary" className={classes.button}>
Secondary
</Button>
<Button variant="outlined" disabled className={classes.button}>
Disabled
</Button>
<Button variant="outlined" href="#outlined-buttons" className={classes.button}>
Link
</Button>
<input
accept="image/*"
className={classes.input}
id="outlined-button-file"
multiple
type="file"
/>
<label htmlFor="outlined-button-file">
<Button variant="outlined" component="span" className={classes.button}>
Upload
</Button>
</label>
</div>
);
}
OutlinedButtons.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(OutlinedButtons);

If you look at this line:
export default withStyles(styles)(OutlinedButtons);
the answer to your question is provided I believe. Material UI has a function withStyles that takes a styles object, and then returns another function that takes a component to return a new component. This is a Higher Order Component, and can be read about on the React docs.
If you look at the linked code of withStyles, you can see the following line where it renders the passed in component:
return <Component {...more} classes={this.getClasses()} ref={innerRef} />;
And is providing the classes prop, making it available to any component exported with withStyles.

Related

Render form on same screen when clicking a button on React, and also saving it on props file?

I want to make the button with the FaPlus icon to render a form OnClick (or OnPress, i've seen that's an option too but i don't know if it makes any difference in comparison) but React says "añadirCurso" (the arrow function) is not defined, any ideas? (i was using part of the code of another question similar to this, but maybe it doesn't work because that code was in a class that extended Component)
Here's the code
import React from "react";
import Button from 'react-bootstrap/Button';
import {aulas} from '../props/aulas';
import Container from 'react-bootstrap/Container';
import AppBar from '#mui/material/AppBar';
import Toolbar from '#mui/material/Toolbar';
import {FaPlus} from 'react-icons/fa';
import { Route, useNavigate } from "react-router-dom";
export default function AdministrarCurso_Preceptor(){
const navigate= useNavigate();
const state= {añadirCurso: false};
añadirCurso= () =>{
return (
<div>
<form method="GET" action="#">
<legend>Añadir Curso</legend>
<label htmlFor="usuario">Nombre de Usuario</label> <br/>
<input required type="text" name="usuario" defaultValue="" /> <br/>
</form>
</div>
)
}
return(
<Container>
<AppBar style={{background: 'transparent', boxShadow: 'none'}}>
<Toolbar>
<Button className="btn btn-success" sx={{flexGrow: 1}}>
<FaPlus/>
</Button>
<Button onClick={()=> navigate('/LoginForm')}>Cerrar Sesión</Button>
</Toolbar>
</AppBar>
<div className="row">
{/* Acá hay un map que muestra todo el contenido del prop aulas
y le asigna un botón dentro de filas y columnas hechas
mientras se toma el contenido del array */}
{aulas.map((aula, i) => (
<div key={i} className="col-md-4" style={{paddingBottom: '10px', paddingTop: '5px'}}>
<Button className={(aula.estado==='sucio'? 'btn btn-danger': 'btn btn-success')}>{aula.año}{aula.division}</Button>
</div>
))}
</div>
</Container>
)
}
And for the "saving it on props" part, as i've said in a previous question i have a props file with classrooms (aulas) and i want the form data to save in that file on Submit, so that when you click on the submit button it saves the data there, and since it's in that file, it should render a new button, is it possible?
There are a couple of reasons regarding why your code is not working.
First of all, as you mentioned the code belonged to a class component and it seems like you simply pasted that in your functional component.
You need to use const before the arrow function's name.
Rather than returning JSX, I'd highly (like really highly) recommend you to use a state like
const [isFormVisible, setIsFormVisible] = useState(false);
and then on click of the button, you just set the state to true. and use the variable for conditional rendering like this....
{isFormVisible && (<theJSXGoesHere />)}

React: How to extract values from Modals?

I have a Chakra UI Modal which opens up onClick of a button. I want to be able to extract the values that a user puts into the inputs/radio buttons when they close the Modal. The Modal class and the Modal/Button render is shown below. Since the input and radio buttons are defined within the Modal class, is it possible to get their final values onClose?
Modal.tsx
import React from 'react'
import {
Modal as ChakraModal,
ModalOverlay,
ModalContent,
ModalHeader,
ModalFooter,
ModalBody,
ModalCloseButton,
RadioGroup,
Stack,
Radio,
VStack
} from "#chakra-ui/react"
import Button from './Button'
import Input from './Input'
type Props = { isOpen : boolean } & { onClose : () => void} & { label : string }
const Modal = ({ label, isOpen, onClose, ...rest }: Props) => (
<ChakraModal {...rest} isOpen={isOpen} onClose={onClose}>
<ModalOverlay />
<ModalContent>
<ModalHeader>{label}</ModalHeader>
<ModalCloseButton />
<ModalBody>
<VStack spacing={4}>
<RadioGroup>
<Stack direction="row">
<Radio value="1">Annually</Radio>
<Radio value="2">Semi-Annual</Radio>
<Radio value="3">Quarterly</Radio>
<Radio value="4">Monthly</Radio>
</Stack>
</RadioGroup>
<Input
label="Custom Interest rate"
name="Custom Interest rate"
/>
</VStack>
</ModalBody>
<ModalFooter>
<Button colorScheme="blue" mr={3} onClick={onClose}>
Save
</Button>
</ModalFooter>
</ModalContent>
</ChakraModal>
)
export default Modal
Render
<Button onClick={onOpen}> Settings </Button>
<Modal
label="Custom Settings"
isOpen={isOpen}
onClose={onClose}
/>
You should probably send a state as the modal's prop.
const [state, setState] = React.useState();
<Modal
label="Custom Settings"
isOpen={isOpen}
onClose={onClose}
onChange={setState}
/>
To get the type of setState, hover over the variable and you can see the type definition.

React Component Re-Renders when updating input using React Hooks

I'm working on a React Project. I'm building a form with about 5 fields in it. I've used React Hooks to manage the state of the updates however when I enter in an input into the field. I can see the component re-render each time I enter a key stroke. the re-render is causing issues because it sets a state of a form field back to empty. Any help would be greatly appreciated!
Thanks,
Link to a gif of the re-render on keystroke can be found here: https://gph.is/g/ZxDqzmN
Link to clearing the form field: https://gph.is/g/4LjmDpd
import React, { useState } from "react";
import styled from "styled-components";
import {
Button,
CardContent,
Dialog,
DialogActions,
DialogContent,
DialogContentText,
DialogTitle,
Card as MuiCard,
Paper as MuiPaper,
TextField,
} from "#material-ui/core";
import { spacing } from "#material-ui/system";
export default function EmployeeFormDialog() {
const [open, setDialog] = useState(null);
const [carName, setCarName] = useState([""]);
const onSubmit = (data, event) => {
event.preventDefault();
console.log(data);
setDialog(false);
};
console.log("re-render");
const Card = styled(MuiCard)(spacing);
const Paper = styled(MuiPaper)(spacing);
return (
<Card mb={6}>
<CardContent>
<Paper mt={4}>
<div>
<Button variant="contained" color="primary" onClick={() => setDialog(true)}>
Add New Cars
</Button>
<Dialog open={open} aria-labelledby="form-dialog-title" disableEnforceFocus="true">
<form onSubmit={onSubmit}>
<DialogTitle id="form-dialog-title">Add New Car</DialogTitle>
<DialogContent>
<DialogContentText>To add new car</DialogContentText>
<TextField
onChange={(e) => setCarName(e.target.value)}
defaultValue={carName}
name="carName"
margin="dense"
id="carName"
label="Car Name"
type="text"
fullWidth
/>
<TextField
autoFocus
name="carYear"
margin="dense"
id="carYear"
label="Car Year"
type="text"
fullWidth
/>
</DialogContent>
<DialogActions>
<Button type="button" onClick={() => setDialog(false)} color="primary">
Cancel
</Button>
<Button type="submit" color="primary">
Add Car
</Button>
</DialogActions>
</form>
</Dialog>
</div>
</Paper>
</CardContent>
</Card>
);
}

How can I get this React Bootstrap Modal Working properly?

I have a exercise I am working on/attempting to replicate and I am trying to add a modal button to the file. I have the button and the modal from React Bootstrap, however, I am unable to get the actual modal to show up. I was using the documentation from React-Bootstrap but getting the actual modal to come up is not working, I have tried to import the various modals but to no avail, am I missing something in my code?
import React from 'react';
import { Modal, Form, FormControl, Button, ButtonToolbar, InputGroup } from 'react-bootstrap';
import { connect } from 'react-redux';
import { addItem } from '../actions/itemActions';
function ItemModal(props) {
return (
<div>
<Button
variant="dark"
style={{marginBottom: '2em'}}
>Add Item
</Button>
<Modal
{...props}
size="lg"
aria-labelledby="contained-modal-title-vcenter"
centered
>
<Modal.Header closeButton>
<Modal.Title id="contained-modal-title-vcenter">
Add to Shopping List
</Modal.Title>
</Modal.Header>
<Modal.Body>
<Form>
<Form.Label for="item">Item</Form.Label>
<InputGroup className="mb-3">
<FormControl
type="text"
name="name"
id="item"
aria-label="Add Shopping Item"
aria-describedby="basic-addon2"
/>
<InputGroup.Append>
<Button onClick={props.onHide} variant="outline-dark">Add</Button>
</InputGroup.Append>
</InputGroup>
</Form>
</Modal.Body>
</Modal>
</div>
);
}
function App() {
const [modalShow, setModalShow] = React.useState(false);
return (
<ButtonToolbar>
<Button variant="dark" onClick={() => setModalShow(true)}>
Add Item
</Button>
<ItemModal
show={modalShow}
onHide={() => setModalShow(false)}
/>
</ButtonToolbar>
);
}
export default connect()(ItemModal);
I do have this extra bit of code that I though would function to open the modal but I don't think it works with this version of Bootstrap?
state = {
modal: false,
name: ''
}
toggle = () => {
this.setState({
modal: !this.state.modal
});
};
onChange = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
From your code snippet, I found an issue.
You have 2 component's in a single file, App and ItemModal. From which App component is your base / parent component and ItemModal is your child component.
But you are exporting child compoennt,
export default connect()(ItemModal);
You should export the parent component,
export default connect()(App);

How to make a Material UI react Button act as a react-router-dom Link?

How can I make a Material UI react Button component act as a Link component from react-router-dom without losing it's original style? Like changing the route on click.
import Button from '#material-ui/core/Button';
<Button variant="contained" color="primary">
About Page
</Button>
To something like this, but maintaining the original Button style:
import Button from '#material-ui/core/Button';
import { Link } from 'react-router-dom';
<Button variant="contained" color="primary">
<Link to="/about">
About Page
</Link>
</Button>
Okay, this is very easy, I don't know why it was not working with me:
Just do like this:
import Button from '#material-ui/core/Button';
import { Link } from 'react-router-dom';
<Button component={Link} to="/about" variant="contained" color="primary">
About Page
</Button>
You can find more details at https://mui.com/material-ui/guides/routing/.
MUI 5 has simplified this even further. Simply provide a MUI Button with a href attribute as follows:
import Button from '#mui/material/Button';
<Button href="/" variant="contained">
Link
</Button>
You need to wrap the <Button /> inside the <Link /> component.
import Button from '#material-ui/core/Button';
import { Link } from 'react-router-dom';
const ButtonWithLink = () => (
<Link to="/about">
<Button variant="contained" color="primary">
About Page
</Button>
</Link>
)
You way worked for me
import Button from '#material-ui/core/Button';
import { useHistory } from 'react-router-dom';
const YourComponentName = () =>{
const history = useHistory();
const handleRoutes = (path) =>{
history.push(path)
}
return(
<>
...
<Button
variant="contained"
color="primary"
onClick={() => handleRoutes('/about')}>
About Page
</Button>
...
</>
)
}

Categories