React menu item hover - reactjs

I am trying React MobX on hover over a list item. Here is my code
export default observer(
class SidebarContent extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.store.fetchSources()
}
toggleHover(){
this.props.store.hover = !this.props.store.hover;
}
getArticles(src) {
this.props.store.fetchArticles(src);
}
render() {
const style1 = this.props.style ? {...styles.sidebar, ...this.props.style} : styles.sidebar;
const { sources, hover } = this.props.store
var linkStyle;
if (this.props.store.hover) {
linkStyle = {backgroundColor: 'black'}
} else {
linkStyle = {backgroundColor: 'white'}
}
const links = sources.map( (src,index) => (
<a key={index} href='javascript:;' style={styles.sidebarLink} onClick={this.getArticles.bind(this, src.id)} >
<span style={linkStyle} onMouseEnter={this.toggleHover.bind(this)} onMouseLeave={this.toggleHover.bind(this)} >
<img className="ui-avaatar image" src='{ src.urlsToLogos.small }' />
<span className="side-news-item"> {src.name} </span>
</span>
</a>
))
return (
<MaterialTitlePanel title="Menu" style={style1}>
<div style={styles.content}>
<div style={styles.divider} />
{links}
</div>
</MaterialTitlePanel>
);
}
}
);
const styles = {
sidebar: {
width: 256,
height: '100%',
},
sidebarLink: {
display: 'block',
padding: '16px 0px',
color: '#757575',
textDecoration: 'none',
},
divider: {
margin: '8px 0',
height: 1,
backgroundColor: '#757575',
},
content: {
padding: '16px',
height: '100%',
backgroundColor: 'white',
},
};
this.props.store.hover is a observable.
The problem is that when mouse over one item, all of the items get the hover effect. What did I do wrong?

Do not set Component's props directly, set it on upper Component.
or you could use state feature, and always use setState() to change state.
write an subcomponent to control the Button State
code below maybe help
class SidebarContent extends React.Component {
constructor(props) {
super(props);
}
componentWillMount() {
this.props.store.fetchSources()
}
getArticles(src) {
this.props.store.fetchArticles(src);
}
render() {
const links = sources.map( (src,index) => <Button />);
return (
<MaterialTitlePanel title="Menu" style={style1}>
<div style={styles.content}>
<div style={styles.divider} />
{links}
</div>
</MaterialTitlePanel>
);
}
}
class Button extends React.Component {
toggleHover(){
this.setState({
hover: !this.state.hover,
});
}
render() {
const style1 = this.props.style ? {...styles.sidebar, ...this.props.style} : styles.sidebar;
const { sources } = this.props.store
const { hover } = this.state;
var linkStyle;
if (hover) {
linkStyle = {backgroundColor: 'black'}
} else {
linkStyle = {backgroundColor: 'white'}
}
return (
<a key={index} href='javascript:;' style={styles.sidebarLink} onClick={this.getArticles.bind(this, src.id)} >
<span style={linkStyle} onMouseEnter={this.toggleHover.bind(this)} onMouseLeave={this.toggleHover.bind(this)} >
<img className="ui-avaatar image" src='{ src.urlsToLogos.small }' />
<span className="side-news-item"> {src.name} </span>
</span>
</a>
);
}
}
const styles = {
sidebar: {
width: 256,
height: '100%',
},
sidebarLink: {
display: 'block',
padding: '16px 0px',
color: '#757575',
textDecoration: 'none',
},
divider: {
margin: '8px 0',
height: 1,
backgroundColor: '#757575',
},
content: {
padding: '16px',
height: '100%',
backgroundColor: 'white',
},
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

Related

react setState not rendering everytime button is pressed

I'm trying to use setState to access my css const mystyle object to change the background color on the squares from blue to red but everytime the button is pressed. It seems everytime I press the button the Setstate does not render on screen any advice or help? Would be greatly appreciated
class MyHeader extends React.Component {
constructor(props){
super(props)
this.state = {backgroundColor: 'blue'};
}
render() {
const mystyle = {
borderRadius: "10px",
background: this.state.backgroundColor,
padding: "10px",
width: "100px",
height: "100px",
marginTop: "10px",
lineHeight: "80px",
color: "dimGrey",
fontWeight: "bold",
fontSize: "3em",
textAlign: "center"
};
function State() {
this.setState({backgroundColor: 'red'})
}
return (
<div>
<h1 style={mystyle}></h1>
<h1>{this.state.backgroundColor}</h1>
</div>
);
}
}
function Test() {
function Test2() {
setchange(change + Math.floor(Math.random() * 10));
if(change > 20) {
setchange(change + Math.floor(Math.random() - 10))
}
}
const [change, setchange] = React.useState(1)
return (
<div>
<h1>click the button to randomize colors</h1>
<button onClick={this.State}>Randomize colors!</button>
<div className='.flex-item'></div>
<h1>{change}</h1>
<div className="flex-item"></div>
<MyHeader />
<MyHeader />
</div>
);
}
ReactDOM.render(<Test />, document.getElementById("root"));
my codepen link to the code
The main issue is trying to do something where the child component, MyHeader, has the function to change state, but trying to invoke it from the parent component, Test. It's just simpler to pass the color as a prop from Test to MyHeader.
Alternatively, you can do the useContext thing, but I think this is easier. I've stripped out all superfluous code that wasn't getting used. You can of course, add them back as you need to.
const MyHeader = ({backgroundColor}) => {
const mystyle = {
borderRadius: "10px",
background: backgroundColor,
padding: "10px",
width: "100px",
height: "100px",
marginTop: "10px",
lineHeight: "80px",
color: "dimGrey",
fontWeight: "bold",
fontSize: "3em",
textAlign: "center"
};
return (
<div>
<h1 style={mystyle}></h1>
<h1>{backgroundColor}</h1>
</div>
);
}
}
const Test = (props) => {
const [backgroundColor, setBackgroundColor] = useState("blue");
const onButtonClick = () => {
setBackgroundColor("red");
}
return (
<div>
<h1>click the button to randomize colors</h1>
<button onClick={onButtonClick}>Randomize colors!</button>
<div className='.flex-item'></div>
<h1>{change}</h1>
<div className="flex-item"></div>
<MyHeader backgroundColor={backgroundColor} />
</div>
);
};

How to delay a component render in React?

I have an instagram widget thas uses iframe, but when I switch between routes, the widget loads too slow and does'nt have time to render properly.
Can You tell me, how to set delay rendering of the component, jr another solution to this problem?
Here is the component:
import React, { Component } from 'react';
const divStyle = [
{
border: 'none',
overflow: 'hidden',
width: '100%'
},
{
font: "10px/14px 'Roboto','Helvetica Neue',Arial,Helvetica,sans-serif",
fontWeight: '400',
width: '100%',
textAlign: 'right'
},
{
color: '#777',
textDecoration: 'none'
}
];
class Instagram extends Component {
render() {
return (
<div id="instagram">
<iframe src="https://snapwidget.com/embed/711808" className="snapwidget-widget" allowtransparency="true" frameborder="0" scrolling="no" style={divStyle[0]}></iframe>
</div>
);
}
}
export default Instagram;
Also the code is located in the CodeSandbox.
Thanks for any help!
This can be possible solution from your code sandbox.
NOTE: Please Replace your loader with loading div.
CodeSandbox: https://codesandbox.io/s/damp-platform-950yw
import React, { Component } from "react";
const divStyle = [
{
border: "none",
overflow: "hidden",
width: "100%"
},
{
font: "10px/14px 'Roboto','Helvetica Neue',Arial,Helvetica,sans-serif",
fontWeight: "400",
width: "100%",
textAlign: "right"
},
{
color: "#777",
textDecoration: "none"
}
];
class Instagram extends Component {
state = {
loading: true
}
handelOnLoad = () => {
this.setState({
loading: false
})
}
render() {
return (
<>
{this.state.loading && <div style={{
position: "fixed",
background: "rgba(0,0,0,0.7)",
top: 0,
bottom: 0,
right: 0,
left: 0,
color: "#fff"
}}>Loading</div>}
<div id="instagram">
<iframe
src="https://snapwidget.com/embed/711808"
className="snapwidget-widget"
allowtransparency="true"
frameborder="0"
scrolling="no"
style={divStyle[0]}
onLoad={this.handelOnLoad}
/>
</div>
</>
);
}
}
export default Instagram;
You can make use of state to render,
class Instagram extends Component {
state={
show: false
}
componentDidMount(){
setTimeout(()=>{
this.setState({show: true})
},5000) //runs after 5sec
}
render() {
return (
<div id="instagram">
{ this.state.show && <iframe src="https://snapwidget.com/embed/711808" className="snapwidget-widget" allowtransparency="true" frameborder="0" scrolling="no" style={divStyle[0]}></iframe> }
</div>
);
}
}

How to make div with selected color in colorpicker

For my app, I use react color picker https://casesandberg.github.io/react-color. I must make add button, and when the user clicks on this button it needs to show div(className is saved-color-placeholder) with the selected color. So, the background of div must be like a selected color. In function saveColor, I push the color in an empty array.
This is my code
class Colorpicker extends React.Component {
constructor(props) {
super(props);
this.state = {
displayColorPicker: false,
color: {
r: '0',
g: '0',
b: '0',
a: '1',
},
colorHex: "#000",
savedColors: []
};
}
handleClick = () => {
this.setState({ displayColorPicker: !this.state.displayColorPicker })
};
handleClose = () => {
this.setState({ displayColorPicker: false })
};
handleChange = (color) => {
this.setState({ color: color })
console.log(color)
};
saveColor = (color) => {
let savedColorsArray = this.state.savedColors;
savedColorsArray.push(this.state.color)
this.setState({
savedColors: savedColorsArray
})
console.log(this.state.savedColors)
}
render() {
const styles = reactCSS({
'default': {
color: {
width: '31px',
height: '31px',
borderRadius: '20px',
background: `rgba(${this.state.color.r}, ${this.state.color.g}, ${this.state.color.b}, ${this.state.color.a})`,
},
popover: {
position: 'absolute',
zIndex: '2',
},
savedColor: {
width: '28px',
height: '28px',
borderRadius: '14px',
marginRight: '8px',
background: `rgba(${this.state.color.r}, ${this.state.color.g}, ${this.state.color.b}, ${this.state.color.a})`
}
},
});
return (
<div className="text-color-container ">
<div className="selected-color-content">
<div className="hex-placeholder">
<p>{this.state.colorHex}</p>
</div>
<div className="switch" onClick={this.handleClick}>
<div style={styles.color} />
</div>
{
this.state.displayColorPicker ?
<div className="wrapper">
<div style={styles.popover}>
<div style={styles.cover} onClick={this.handleClose} />
<SketchPicker color={this.state.color} onChange={this.handleChange} />
<div className="saved-colors">
<span >Saved colors</span>
<div className="painted-colors">
<button onClick={this.saveColor} className="btn-save-color">Add</button>
<span slassName="saved-color-placeholder">
<div style={styles.savedColor}/>
</span>
</div>
</div>
</div>
</div>
:
null
}
</div>
</div>
)
}
}
export default Colorpicker
I am not sure this is the best solution but I think it can be good enough.
You can use arrays inside your style prop. So what you could do is:
<div style={[styles.savedColor,{backgorundColor: selectedColor}]>
Hope this will helps.

Toggle Button Group in React

New to react and trying to use in a new electron learning project I have. I'm trying to build a really basic drawing app.
I created a ToolbarButton class. That would represent each button and a Toolbar that would manage the button group. Example If you pick a 'primary' tool then it should turn off all other primary tools and leave only your current selection.
In jQuery I'd just do something like
let button = $(this);
let toolbar = $(this).parent();
toolbar.find('button.toolbar-button').removeClass('active');
button.addClass('active');
How would I do the same in react? I can toggle what I want to with setState from within the ToggleButton but separating it out into a prop seems to be an answer, but then I need to have the Toolbar manage the button 'active' states and I'm not sure how to do that. Think the answer is in ReactDOM, super newbie to react so apologize if the answer is overly obvious.
import React from 'react';
import FontAwesome from 'react-fontawesome';
import { ButtonGroup } from 'react-bootstrap';
import { ChromePicker} from 'react-color';
class ToolbarButton extends React.Component
{
state =
{
active: false
}
handleClick = ()=> {
if(this.props.onClick)
{
this.props.onClick();
}
this.setState({ active: !this.state.active});
}
render(){
return <div className={`btn btn-primary${this.state.active ? ' active' : ''}`} onClick={this.handleClick}>{this.props.children}</div>
}
}
class ColorPickerButton extends React.Component
{
constructor(props)
{
super(props);
this.state = {
displayColorPicker: false,
color: { r: 255, g: 255, b: 255, a:1 }
}
}
state = {
flyout: 'bottom',
displayColorPicker: false,
color: { r: 255, g: 255, b: 255, a:1 }
}
/* This button should have an option to display how the colorpicker flys out */
static flyoutStyles =
{
normal: { },
top: {top: '0px' },
bottom: { top: '100%' },
left: { right: '100%' },
right: { left: '100%' }
}
handleClick = (e) => {
this.setState({ displayColorPicker: !this.state.displayColorPicker});
}
handleClose = () => {
this.setState({ displayColorPicker: false });
}
handleChange = (color) => {
this.setState({ color: color.rgb });
}
stopPropagation = (e) => {
e.stopPropagation();
}
render()
{
const swatchStyle = {
backgroundColor: `rgba(${this.state.color.r},
${this.state.color.g},
${this.state.color.b},
${this.state.color.a})`,
height: '16px',
width: '16px',
border: '1px solid white'
};
const popup = {
position: 'absolute',
zIndex: 2,
top: 'calc(100% + 2px)'
};
const cover = {
position: 'fixed',
top: '0px',
right: '0px',
left: '0px',
bottom: '0px',
};
return (
<ToolbarButton onClick={this.handleClick} active={this.state.displayColorPicker}>
<div style={swatchStyle} />
{
this.state.displayColorPicker ?
<div style={popup} onClick={this.stopPropagation}>
<div style={ cover } onClick={ this.handleClose }/>
<ChromePicker color={this.state.color} onChange={this.handleChange} />
</div>
: null
}
</ToolbarButton>
);
}
}
export class CanvasToolbar extends React.Component
{
handleClick = (e) => {
}
render(){
return (<div className="CanvasToolbar">
<ButtonGroup vertical>
<ToolbarButton>
<FontAwesome name='paint-brush' />
</ToolbarButton>
<ToolbarButton>
<FontAwesome name='eraser' />
</ToolbarButton>
<ToolbarButton>
<FontAwesome name='magic' />
</ToolbarButton>
<ColorPickerButton />
</ButtonGroup>
</div>);
}
}

react-burger-menu css does not work

I'm using burger-menu and i can't set CSS for the burger menu like the author guide: https://github.com/negomi/react-burger-menu
Here's my burger menu component:
import React from 'react';
import BurgerMenu from 'react-burger-menu';
import { List, ListItem, ListItemContent } from 'react-mdl';
var MenuWrap = React.createClass({
getInitialState() {
return {hidden : false};
},
toggle() {
this.setState({hidden: !this.state.hidden});
},
render() {
let style;
if (this.state.hidden) {
style = {display: 'none'};
}
return (
<div style={style} className={this.props.side}>
{this.props.children}
</div>
);
}
});
export default class LeftSidebar extends React.Component {
constructor(props) {
super(props);
this.state = {
currentMenu: 'push',
side: 'left',
hidden: true,
};
};
render() {
const Menu = BurgerMenu[this.state.currentMenu];
var styles = {
bmBurgerButton: {
position: 'fixed',
width: '36px',
height: '30px',
left: '36px',
top: '36px'
},
bmBurgerBars: {
background: '#373a47'
},
bmCrossButton: {
height: '24px',
width: '24px'
},
bmCross: {
background: '#bdc3c7'
},
bmMenu: {
background: '#373a47',
padding: '2.5em 1.5em 0',
fontSize: '1.15em'
},
bmMorphShape: {
fill: '#373a47'
},
bmItemList: {
color: '#b8b7ad',
padding: '0.8em'
},
bmOverlay: {
background: 'rgba(0, 0, 0, 0.3)'
}
};
return (
<MenuWrap wait={20}>
<Menu
style={styles}
noOverlay id={this.state.currentMenu}
pageWrapId={'page-wrap'}
outerContainerId={'outer-container'}
>
{console.log(Menu)}
<List>
<ListItem>
<ListItemContent icon="person">Dashboard</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent icon="person">Community</ListItemContent>
</ListItem>
<ListItem>
<ListItemContent icon="person">About</ListItemContent>
</ListItem>
</List>
</Menu>
</MenuWrap>
);
}
};
And here is my main component:
import React from 'react';
import styles from './Main.scss';
import LeftSidebar from '../LeftSidebar/LeftSidebar'
export default class Program extends React.Component {
render() {
return (
<div id="outer-container" style={{height: '100%'}}>
<LeftSidebar />
<div id="page-wrap">
<p>Content</p>
</div>
</div>
);
}
}
All of the css from variable styles does not work.
EDIT: the problem above is solved by change style ={styles} to styles = {styles}. The other problem is: when i click close, the sidebar menu shift down about 10 or 20px before moving back to the left. How to remove that shift down effect?
Seems like you have a typo. It should be styles={styles} instead of style={styles}.

Resources