Material-UI ripple/hover effect carrying over to newly mounted component - reactjs

I am experiencing an issue with Material-UI's ripple effect when mounting/un-mounting button components. I have some buttons which toggle state, and the button which is displayed is based on this state. The problem is that when I click the button to toggle this state, and the new button is rendered, the ripple/hover effects that were applied from the previous button carries over to the newly mounted button.
Here is a simplified example of this issue on codepen.
Does anyone know why this is happening, and how to prevent this behavior?

React (and thus Material-UI) thinks they are the same button with changed props. You can make React realize they are different buttons by giving them distinct keys (e.g. "button1" and "button2" in my altered version of your sandbox): https://codesandbox.io/s/competent-fermat-q9ojt?file=/src/demo.js.
export function SingleButtonExample() {
const classes = useStyles2();
const [displayedButton, setDisplayedButton] = useState(1);
const toggleDisplayedButton = () =>
setDisplayedButton(displayedButton === 1 ? 2 : 1);
const button1 = (
<Button
key="button1"
variant="contained"
color="primary"
onClick={toggleDisplayedButton}
>
Show Button 2
</Button>
);
const button2 = (
<Button
key="button2"
variant="contained"
color="secondary"
onClick={toggleDisplayedButton}
>
Show Button 1
</Button>
);
return (
<div className={displayedButton === 1 ? classes.button1 : classes.button2}>
{displayedButton === 1 ? button1 : button2}
</div>
);
}
Another way to handle this (which may be more convenient in some cases) is just to make sure the two buttons have a different spot in the JSX:
return (
<div className={displayedButton === 1 ? classes.button1 : classes.button2}>
{displayedButton === 1 && button1}
{displayedButton !== 1 && button2}
</div>
);
This will become either <div>{false}<Button/></div> or <div><Button/>{false}</div> which still allows React to tell that they are different buttons.

Related

I need help to selecting a button from an array of buttons using material ui

So things are like this, I have an array of phone numbers, it's mapped so everynumber has a button to copy the number and make a call. Thing is, we use material-ui, specifically the v4 of it.
What i need to do is that whenever someone clicks a button this button change it's color to idk green let's say so the worker knows they are using that button, avoiding clicking again and those kind of things.
material-ui has it's own way to put a color to the button using the color prop and the createTheme API, is there ANY way to do this using &:active or &:selected in material with the createTheme API, is there a way to do it without it (it's not mandatory to use createTheme).
Any help is appreciated, thanks!
If you are rendering your buttons using a map, store the index of the button that is clicked in some state, and use it to compare the index of the current button with that stored index, if matches change the color
something like:
export default function App() {
const [active, setActive] = useState(null);
return (
<div className="App">
{buttons.map((button, idx) => {
const isActive = active === idx;
return (
<Button
key={`btn-${idx}`}
onClick={() => setActive(idx)}
variant="contained"
color={isActive ? "success" : "primary"}
>
{button}
</Button>
);
})}
</div>
);
}

React toggling between clickable words that pull up <Elements/>

Somewhat new to React.
I want to be able to toggle between React elements CreateUser, EditUser, and ListUser.
It would be great to have a clickable text that when selected pulls up that element and its
corresponding stuff. In the case of Create its a field with a save button.
What is the best way to have my CrudSelector class list all three texts, make them clickable and pull up the stuff inside toggling to the selected one at a time?
Welcome. Always a good idea to share code with your question.
You'll want to use some kind of state which tells your parent component which child component to show. Kind of like this in your React functional component:
const [ featureToShow, setFeatureToShow ] = useState('list')
return (
<>
{/* Show some buttons to change the state */}
<button onClick={() => setFeatureToShow('list')}>Show User List</button>
<button onClick={() => setFeatureToShow('create')}>Create User</button>
<button onClick={() => setFeatureToShow('edit')}>Edit User</button>
{/* Depending on what is in the state show that component */}
{ featureToShow === 'list' ? <ListUser /> : null }
{ featureToShow === 'create' ? <CreateUser /> : null }
{ featureToShow === 'edit' ? <EditUser /> : null }
</>
)
In reality you'll probably want to enable clicking on the user's name in ListUser to show the EditUser component.

The action menu is not getting closed even if I click somewhere on page, the menu remains open until I explicitly click on the Action button again

//This is dropdown component
const Dropdown: FC<any> = ({ list, item, title },props) => {
const isDisabled = item && item.users.length > 0 ? false : true;
const [show, setShow] = useState(false);
const toggleMenu = () => {
setShow(!show);
};
return (
<div>
<Button
title={title || "Action"}
onClick={toggleMenu}
iconName="downarrow"
iconPosition="left"
variant="outlined"
color="primary"
/>
)
The action menu is not getting closed even if I click somewhere on page, the menu
remains open until I explicitly click on the Action button again.
If you want the action menu to close when you click anywhere on the page using onClick won't help it. Use onBlur and use it on the button as -
<Button
title={title || "Action"}
onClick={toggleMenu}
onBlur={() => setShow(true)}
iconName="downarrow"
iconPosition="left"
variant="outlined"
color="primary"
/>
Or alternatively, what you can do is -
Create a reference to your outer div.
Add event listener mousedown (or click) to the document whenever this component appears on screen (eg. mount) and also don’t forget to remove the event on unmount too.
Inside the event (handleClick) this.{Any ref name you give}.contains(e.target) will return true if whatever you are clicking is inside the “node” ref.
Now you have it, you can now do whatever you feel like, close the modal, close the dropdown menu list, anything is allowed.
The above 4 points were taken from the article - https://medium.com/#pitipatdop/little-neat-trick-to-capture-click-outside-react-component-5604830beb7f.

react-resize-observer returns null values with Bootstrap modal

I'm trying to detect a container size change with react-resize-observer. To do so, I have embeded a ResizeObserver in a custom component of mine.
It works great when the component is used in isolation. However, as soon as it is used in a Bootstrap modal (from react-bootstrap), ResizeObserver's onResize callback is called with null values (width === height === 0).
What am I doing wrong?
The problem comes from the way the modal is displayed: with an animation. When the modal component is first rendered, it is hidden, thus react-resize-observer reports null values.
Instant fix
Turn the animation off:
<Modal
animation={false}
>
At least, you should give this a try, just to make sure that fixes the issue.
Make react-resize-observer work while keeping the animation
The trick is to start displaying ResizeObserver and its parent component only when the modal animation has actually started, thanks to the onEntering callback:
export const MyModal = () => {
const [ showComponent, setShowComponent ] = useState(false);
return (
<Modal
onEntering={() => setShowComponent(true)}
>
{showComponent && (
<div>
<ResizeObserver onResize={(rect) => {...}}/>
...
</div>
)}
</Modal>
);
}

ReactJS buttons change color on click

I have 3 buttons in reactjs created with Material UI Buttons.
<>
<Button variant="contained">Button 1</Button>
<Button variant="contained">Button 2</Button>
<Button variant="contained">Button3</Button>
</>
How can I make that when clicking on one, it changes it's color (let's say blue) and the other ones reset to Default?
Because React use JSX, you can put javascript in your html component.
We can imagine a single state that manage your buttons.
in your component you create a state containing integer
const [buttonSelected, setButtonselected] = useState(0);
I'm using the react hook syntax, but it also depend on you implementation.
buttonSelected is the current value of the state and setButtonselected is the function that change the state. When you call it, React will rerender your component and change the display .
You can now add a click function on your return
...
<Button variant="contained" onClick={() => setButtonSelected(1)}>Button 1</Button>
<Button variant="contained" onClick={() => setButtonSelected(2)} >Button 2</Button>
<Button variant="contained" onClick={() => setButtonSelected(3)}>Button3 </Button>
...
This will change the value of buttonSelected each time you click a button.
We now need to change the color , for that we will use use makeStyle, but there is other way to do so.
First, create a style element outside of your component.
const useStyles = makeStyles((theme: Theme) =>
createStyles({
selected: {
background: 'blue',
},
default:{
background: 'default',
}
}
),
);
Then call it in your component
const classes = useStyles();
And finally you can set the style that you want depending on the value
...
<Button className={(buttonSelected === 1) ? classes.selected : classes.default} variant.....
<Button className={(buttonSelected === 2) ? classes.selected : classes.default} variant.....
<Button className={(buttonSelected === 3) ? classes.selected : classes.default} variant.....
...
This is a ternary operator, it's the equivalent of
if(buttonSelected === 1){
return classes.selected
} else {
return classes.default
}
And it should work.
You can learn about it in the conditional rendering of react and in the the styling in react
Dont hesitate if you got any questions :)

Resources