How to reuse a Custom Material-ui button inside a react-app? - reactjs

I'm developing my first React app. I've imported a Material-ui button and I've customized it.
Now I want to reuse this custom button in several components of my app. I want a different text for each time I use this custom button.
Where do I need to write this specific text for each button?
My button is visible when I import it in other components, but I can't see the text I wrote inside the button component. The button stays empty.
My custom button component : MyButton:
import React from "react";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
const styles = () => ({
button: {
margin: 50,
padding: 10,
width: 180,
fontSize: 20
}
});
function MyButton(props) {
const { classes } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b> </b>
</Button>
);
}
export default withStyles(styles)(MyButton);
The other component where I import MyButton component : Home :
import React from "react";
import "../App.css";
import MyButton from "./Button";
function Header() {
return (
<header className="Header">
{/* background image in css file */}
<h1>Welcome </h1>
<h3> description...</h3>
<MyButton>Play now</MyButton>
</header>
);
}
export default Header;
I expect the button to show "Play now" (expected output) but for now it stays empty (actual output).

Also, I've found another solution that offers the possibility to write directly the text inside each button (children of MyButton), and customize it if needed.
Pass "children" keyword as "props" to MyButton component :
function MyButton(props) {
const { classes, children } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b>{children}</b>
</Button>
);
}
Then write the text of your button inside the button as you will do in html :
<MyButton> Play now </MyButton>

You will get the most flexibility from your custom Button if you pass all of the props along to the wrapped Button. This will automatically take care of children and classes so long as you use class keys in your styles object that match the CSS classes supported for the wrapped component.
import React from "react";
import Button from "#material-ui/core/Button";
import { withStyles } from "#material-ui/core/styles";
const styles = () => ({
root: {
margin: 50,
padding: 10,
width: 180,
fontSize: 20,
fontWeight: "bold"
}
});
function CustomButton(props) {
return <Button variant="contained" color="primary" {...props} />;
}
export default withStyles(styles)(CustomButton);
Notice in the sandbox example, that this allows you to still leverage other Button features like disabled, specify additional styles, or override some properties specified in CustomButton.
If you have a scenario where you need to handle children explicitly (in my example above I used fontWeight CSS instead of the <b> tag), you can use the following syntax to still pass all the props through to the wrapped component:
function CustomButton({children, ...other}) {
return <Button variant="contained" color="primary" {...other}><b>{children}</b></Button>;
}

Pass text of button as props to your button component
<MyButton text="Play now"></MyButton>
Then inside MyButton component you can get it like
function MyButton(props) {
const { classes,text } = props;
return (
<Button variant="contained" color="primary" className={classes.button}>
<b> {text} </b>
</Button>
);
}

Related

Im building a React App that requires a pdf to download, in the event the (materialUI) download button is clicked, how can I add that functionality?

the profile component contains the following code:
<div className="button_container" style={{display:'flex'}}>
<DownloadButton text={'PDF'} icon={<GetAppIcon />} />
</div>
the button component contains the following code:
import React from 'react'
import { Button } from "#material-ui/core";
import './Button.css'
const DownloadButton = ({text, icon}) => {
return (
<Button onClick={() => { }} className="custom_btn" endIcon={icon ?
(<div className="btn_icon_container" >{icon}</div>) : null}>
<span className="btn_textw">{text}</span>
</Button>
)
}
export default CustomButton
**I've added an onClick event but am having difficulty figuring the simplest way to trigger the file to download, once the button is clicked **
Any comments are appreciated
Turn your button into a link and provide the path to your pdf file
import React from 'react'
import { Button } from "#material-ui/core";
import './Button.css'
const DownloadButton = ({text, icon}) => {
return (
<Button component="a" href="PATH_TO_YOUR_PDF_FILE" className="custom_btn" endIcon={icon ?
(<div className="btn_icon_container" >{icon}</div>) : null}>
<span className="btn_textw">{text}</span>
</Button>
)
}
export default CustomButton
The simplest way to achieve this is to use an HTML anchor and style it like a button.
Download PDF
With material core buttons you need to add the href prop and it will use an anchor tag instead of a button tag.
<Button href="/path/to/file.pdf">Download PDF</Button>
Your download button would look like
const DownloadButton = ({text, icon}) => {
const endIcon = icon ? (<div className="btn_icon_container" >{icon}</div>) : null;
return (
<Button href="file.pdf" className="custom_btn" endIcon={endIcon}>
<span className="btn_textw">{text}</span>
</Button>
)
}

react How to hide the Card when another location is pressed

Developed with react and typescript.
Now the card is shown or hidden when you click on the div tag.
I want to hide the Card when it is displayed, even if another place other than the div tag is pressed.
import React, { FunctionComponent, useState } from 'react';
import { Card } from 'components/atoms/Card';
import { Display } from 'components/atoms/Display';
const Test: FunctionComponent = () => {
const [isDisplay, setIsDisplay] = useState(false);
const onClick = () => {
setIsDisplay(!isDisplay);
};
return (
<>
<div onClick={onClick} style={{ width: '100px', height: '100px' }}>
display Card
</div>
<Display enabled={isDisplay}>
<Card width={100} height={100}></Card>
</Display>
</>
);
};
export default Test;
Try this in your onClick method. It looks like you need to access the current state's value and update it.
setIsDisplay(state => !state);
It's explained here in the React docs.
https://reactjs.org/docs/hooks-reference.html#functional-updates

How do you use Pseudo-classes in React using css modules?

The example I worked on is the following:
I have a button component that receives the background color as props. The received color will be the background that the button must have when hovering.
Second question:
The only way to use props in css, using css modules, is to apply the inline style in the js file where you declare the component?
Below I insert a code base (in the example the background color is applied by default):
import Button from "./Button";
export default function App() {
return <Button hoverColor={"red"} />;
}
...
export default function Button({ hoverColor }) {
const buttonStyle = {
backgroundColor: hoverColor
};
return <button style={buttonStyle}>click me!</button>;
}
Thanks
You may use React useState Hook to achieve the desired functionality: (Your Button component should look like this)
import React, { useState } from "react";
export default function Button({ hoverColor }) {
const [color, setColor] = useState("");
const buttonStyle = {
backgroundColor: color
};
return (
<button
style={buttonStyle}
onMouseOver={() => setColor(hoverColor)} //set the color when user hovers over the button
onMouseOut={() => setColor("")} //set color to an empty string otherwise
>
click me!
</button>
);
}

fortawesome/react-fontawesome package change icon onclick

I have the following icon in my code:
<FontAwesomeIcon id="star" onClick={this.handleClick} icon={hollowstar} size="lg" />
I need the icon to change from hollowstar to solidstar onclick. How can this be accomplished?
You can do something like this:
import { faStar as fasFaStar } from '#fortawesome/free-solid-svg-icons';
import { faStar as farFaStar } from '#fortawesome/free-regular-svg-icons';
// ...
const [star, setStar] = useState(farFaStar);
// ...
<FontAwesomeIcon
onClick={() => {
setStar(fasFaStar);
}}
icon={star}
// Other props...
/>
So in the code we import the same star icon with different styles like described in the documentation here: https://github.com/FortAwesome/react-fontawesome#how-do-i-import-the-same-icon-from-two-different-styles.
Since the icon is just an object you can save it to the state and update the state to the other icon inside an onClick function.
For clarity, I've used a functional component here.

Material-UI ListItem Component for Right Toggle

This seems so basic that I feel I must be misunderstanding how it works. I have a simple demo component that renders a material-ui List with three ListItems. Each list item has a toggle on the right hand side implemented using the rightToggle prop. For the purposes of demonstration each toggle is generated differently.
The first is a basic material-ui Toggle component. The second is a custom component wrapping a Toggle and the third is generated by a function call.
Some code:
import React from 'react';
import Paper from 'material-ui/Paper';
import { List, ListItem } from 'material-ui/List';
import Toggle from 'material-ui/Toggle';
import MyToggleComponent from './MyToggleComponent';
const myToggleFunction = id => <Toggle onClick={() => console.log(id)} />;
const TestPage = () =>
<div>
<Paper style={{ width: 500, padding: 15, margin: 25 }}>
<List>
<ListItem
primaryText="This is the first list item"
secondaryText="This toggle for this item is directly defined"
rightToggle={<Toggle onClick={() => console.log('1 - clicked')} />}
/>
<ListItem
primaryText="This is the second list item"
secondaryText="This toggle is generated from a component"
rightToggle={<MyToggleComponent text="2 - clicked" />}
/>
<ListItem
primaryText="This is the third list item"
secondaryText="This toggle is generated programatically"
rightToggle={myToggleFunction('3 - clicked')}
/>
</List>
</Paper>
</div>;
export default TestPage;
and the custom component - very basic
import React from 'react';
import PropTypes from 'prop-types';
import Toggle from 'material-ui/Toggle';
const MyToggleComponent = ({ text }) => <Toggle onClick={() => console.log(text)} />;
MyToggleComponent.propTypes = {
text: PropTypes.string.isRequired,
};
export default MyToggleComponent;
Results in:
All three toggles generate the expected console output. The first and third items render as I would expect with a Toggle to the right of the list item. But the second, using a custom component, renders the Toggle above the list item. Can anyone explain why?
Material-UI is cloning these elements under the hood and is adding/injecting a prop style. In the first and third example the actual values are the Material UI defined components that accept a property style as documented here. Your own defined component however only passes the text property and does nothing with style.
So comes down to that all 3 examples get passed a style prop but only the first and third do something with it. To bad this wasn't well documented.
It kinda does say it needs to be a Toggle element and your own component isn't one because it wraps the Toggle component.
pushElement(children, element, baseStyles, additionalProps) {
if (element) {
const styles = Object.assign({}, baseStyles, element.props.style);
children.push(
React.cloneElement(element, { // element is your own defined component
key: children.length,
style: styles, // here the style property is passed
...additionalProps, // your text property is passed here
})
);
}
}
source
So to fix this change:
const MyToggleComponent = ({ text }) => <Toggle onClick={() => console.log(text)} />;
to:
const MyToggleComponent = ({ text, style }) =>
<Toggle style={style} onClick={() => console.log(text)} />;

Resources