css are not aplying - javascript

enter image description here
I try to change button color via applying styles.css to button component. Component button got className for switching from reducer. After done condition in reducer className in button component got its correct value, but color not switch.... any ideas why?
please see
"
button key={id} className ={props.optionStyle}
"
reduser.js
....
if (newOption.option === answer) {
return {
...state,
userAnswer: newOption.option,
answer: answer,
answerTrue: true,
currentSrc: currentSrcT,
questAudio: false,
optionStyle: "styles.correct"
};
......
component with button
import React from 'react';
import styles from './item.css';
const OptionItem = (props) => {
const { option, image, id} = props.optionAnswer ;
const { onChoiseOption} = props ;
const onButtonChose = (id) =>{
if(props.answerTrue) {
}
}
const onChoiseOptionComp = e => {
onChoiseOption(),
onButtonChose(id)
}
return (
<div>
<button key={id} className={props.optionStyle}
onClick={
onChoiseOptionComp
}
>
{option}
<p ><img src={image} alt="cartinka" className={styles.imageOption}/></p>
</button>
</div>
)
};
item.css
.imageOption {
width: 300px;
padding-bottom: 10px;
}
.optionChose {
background-color: blue;
}
.correct {
background-color: crimson;
}
.nonCorrect {
background-color: #2ddc66;
}
.....if I tried to change className manually - that work fine

I think you are trying to use CSS modules in runtime code, and this won't work because it gets resolved before the code is built/ran.
optionStyle: "correct" in reducer looks more reasonable.
Secondly, your reducer gives you a string value "styles.correct" that is not the same as the variable styles.correct. This is one way to fix it:
className={ props.optionStyle === "correct" ? styles.correct : styles.nonCorrect }

Related

how to add class and remove class from buttons in react?

I have 20 buttons and I wanted to apply class .active on the button which is clicked and the rest will inactive. Suppose I clicked on button one then I want to add an active class to button one and then when I clicked on button two then button two will get an active class and active class removed from button one.
import React from "react";
const PaginationButtonsList = (props) => {
const handleClick = (event) =>{
}
return (
<div className="pagination-buttons-list">
<button onClick={handleClick} id="button-1">1</button>
<button onClick={handleClick} id="button-2">2</button>
<button onClick={handleClick} id="button-3">3</button>
<button onClick={handleClick} id="button-4">4</button>
<button onClick={handleClick} id="button-5">5</button>
<button onClick={handleClick} id="button-6">6</button>
<button onClick={handleClick} id="button-7">7</button>
<button onClick={handleClick} id="button-8">8</button>
<button onClick={handleClick} id="button-9">9</button>
<button onClick={handleClick} id="button-10">10</button>
<button onClick={handleClick} id="button-11">11</button>
<button onClick={handleClick} id="button-12">12</button>
<button onClick={handleClick} id="button-13">13</button>
<button onClick={handleClick} id="button-14">14</button>
<button onClick={handleClick} id="button-15">15</button>
<button onClick={handleClick} id="button-16">16</button>
<button onClick={handleClick} id="button-17">17</button>
<button onClick={handleClick} id="button-18">18</button>
<button onClick={handleClick} id="button-19">19</button>
<button onClick={handleClick} id="button-20">20</button>
</div>
);
};
export { PaginationButtonsList };
I assume that you don't want a button with just generic numbers for text. So you will need to:
create an array list with all text that you want to set to the button
Then render all of it through the map and bind the onClick event to take the index
on click you should set that index in state and check which button
has that index so set it to active
.
import React, {useState} from "react";
/* Change this number to any text and add as many as you need */
let buttonText = ['1','2','3','4','5']
const PaginationButtonsList = (props) => {
const [activeIndex, setActiveIndex] = useState(-1)
const handleClick = (value) =>{
setActiveIndex(value)
}
return (
<div className="pagination-buttons-list">
{buttonText.map((text,index)=> (
<button onClick={()=>handleClick(index)} class={index === activeIndex ? "active" :""} id={`button-${index}`}>{text}</button>
)
</div>
);
};
export { PaginationButtonsList };
One way of approaching this would be to create an array of button objects that you can use to configure your component. Each button object in the array would have the shape { id: number, text: string, active: boolean } that defines it. You can that add that configuration to state.
When a button is clicked you reset the active values of each button (by updating a deep-copy the current state), update the active value of the clicked button, and finally create a new state with the updated data. That new state will be reflected in the component when it's re-rendered.
This method also has the advantages that 1) you encapsulate the button config in one place without the need for separate states, and 2) you don't need to hard-code all the buttons in the JSX - you can map over the button configuration to create an array of buttons using a useful Button component.
const { useState } = React;
// Pass in the button config
function Example({ btnConfig }) {
// Set state with the config
const [ btns, setBtns ] = useState(btnConfig);
// When a button is clicked grab its id from its dataset,
// make a deep copy of the state resetting all of the active
// values for each button to false, find the index of the button
// that was clicked, and then set its active value to true.
// Finally update the state to re-render the component
function handleClick(e) {
const { id } = e.target.dataset;
const reset = btns.map(btn => ({ ...btn, active: false }));
const index = reset.findIndex(btn => btn.id === +id);
reset[index].active = true;
setBtns(reset);
}
// `map` over the state and create JSX using a
// Button component passing down the properties from
// the objects in state as well as a reference to the
// `handleClick` function
return (
<div>
{btns.map(btn => {
const { id, text, active } = btn;
return (
<Button
key={id}
id={id}
active={active}
text={text}
handleClick={handleClick}
/>
);
})}
</div>
);
}
// Accepts the button props and returns a button. If
// the active value is true then apply the "active" class
function Button({ id, text, active, handleClick }) {
return (
<button
data-id={id}
onClick={handleClick}
className={active && 'active'}
>{text}
</button>
);
}
// Create a button config - an array of button of objects
const btnConfig = Array.from({length: 10}, (_, i) => {
const id = i + 1;
return { id, text: id, active: false };
});
// Pass in the button config to the component
ReactDOM.render(
<Example btnConfig={btnConfig} />,
document.getElementById('react')
);
button { margin-right: 0.5em; font-size: 1.2em; border-radius: 5px; padding: 0 0.4em; }
button:hover { cursor: pointer; background-color: #cdcdcd; }
button.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
<div id="react"></div>
You only need to save a single integer of state, the index corresponding to the active button -
function App({ buttons = [] }) {
const [active, setActive] = React.useState(-1)
const toggle = index => event => setActive(index)
return <div>
{buttons.map((b, key) =>
<button
className={active == key && 'active'}
onClick={toggle(key)}
children={b}
/>
)}
</div>
}
ReactDOM.render(
<App buttons={["🍟","🥨","🍐","🌮","🥤"]} />,
document.body
)
button { margin-right: 0.5em; font-size: 1.2em; border-radius: 5px; padding: 0 0.4em; }
button:hover { cursor: pointer; background-color: #cdcdcd; }
button.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
If you want repeated clicks to the same button to toggle the active off, if the same button is clicked twice, you can restore the initial active state of -1 -
function App({ buttons = [] }) {
const [active, setActive] = React.useState(-1)
const toggle = index => event =>
setActive(index == active ? -1 : index) // <-
return <div>
{buttons.map((b, key) =>
<button
className={active == key && 'active'}
onClick={toggle(key)}
children={b}
/>
)}
</div>
}
ReactDOM.render(
<App buttons={["🍟","🥨","🍐","🌮","🥤"]} />,
document.body
)
button { margin-right: 0.5em; font-size: 1.2em; border-radius: 5px; padding: 0 0.4em; }
button:hover { cursor: pointer; background-color: #cdcdcd; }
button.active { background-color: lightgreen; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.14.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.14.0/umd/react-dom.production.min.js"></script>
You can create an array state holding information for each button.
In each button state object in the array, include a property for whether the button is active or not. Then use this property when mapping the button states to actual buttons and set the active class if the button's state is active.
When a button is clicked, update the state array: make that button's state active and make every other button's state inactive.
Here's a complete example with types:
import {default as React, type ReactElement, useState} from 'react';
type ButtonState = {
active: boolean;
id: number;
};
const PaginationButtonsList = () => {
const [buttonStates, setButtonStates] = useState<ButtonState[]>(Array.from(
{length: 20},
(_, i) => ({id: i + 1, active: false}),
));
const createButtonFromState = (
{active, id}: ButtonState,
index: number,
): ReactElement => {
const setActiveExclusive = () => {
setButtonStates(arr => arr.map((state, i) => ({
...state,
active: i === index,
})));
};
const buttonProps = {
className: active ? 'active' : '',
id: `button-${id}`,
key: id,
onClick: setActiveExclusive,
};
return (<button {...buttonProps}>{id}</button>);
};
return (
<div className="pagination-buttons-list">
{buttonStates.map(createButtonFromState)}
</div>
);
};
Code in the TypeScript Playground

How to change image src when onMouseEnter div in react stateless component

I'm beginner in react.
I want to change my image src when mouse enter the div.
Here is my code.
const CategoryImage = styled.img.attrs(props => ({
src: props.url,
}))`
width: 80px;
height: 80px;
margin: 5px auto;
`;
let imgUrl = ``;
const Category = ({ categoryItems }) => {
function handleHover(category) {
const {
category: { hoverUrl },
} = category;
// console.log(hoverUrl);
imgUrl = hoverUrl;
}
function handleUnHover(category) {
const {
category: { url },
} = category;
// console.log(url);
imgUrl = url;
}
return (
<Container>
<Grid>
{categoryItems.map(category => (
<CategoryContainer
key={category.id}
onMouseEnter={() => handleHover({ category })}
onMouseLeave={() => handleUnHover({ category })}
>
<CategoryImage url={imgUrl} alt={category.name} />
<CategoryName key={category.id}> {category.name} </CategoryName>
</CategoryContainer>
))}
</Grid>
</Container>
);
};
Can I change image without using state?
Most of Questions usually use state to change image. I think state isn't needed when changes occurs in my case(codes) though.
And, I heard that performance usually better without using state. Is that right?
Always Appreciate u guys:)
In case of 2 images , just add css property. Hide it by display none , and position all the images at top ....
On mouse over or enter , in this event , pass the class name , that's it .....
I did this task long back, but can't remember exactly what I had done ,
Try this

Having trouble with typeahead/predictive test functionality

I'm using material-table and I decided to implement a "typeahead" kind of feature that Google has. Something like this:
To realize this, I wrapped the MTableEditField component with my own, which looks like this:
import React, { useState } from "react";
import { MTableEditField } from "material-table";
const CustomTableEditField = props => {
const [rawValue, setRawValue] = useState(props.value);
const [suggestedValue, setSuggestedValue] = useState("asdasda");
const handleOnChange = value => {
// ... logic to find best match and set state values
};
return (
<MTableEditField
inputProps={
suggestedValue
? {
style: {
backgroundColor: "#557D92",
color: "white",
padding: "offset"
}
}
: {}
}
{...props}
value={suggestedValue ?? rawValue}
onChange={handleOnChange}
/>
);
};
export default CustomTableEditField;
The problem is that when there is a value, it looks like:
I don't want it to change the whole background if there will be a match. I want it to keep the already-typed text, with suggested text appended to it.
I looked into gradients, which are treated as images that can be resized, but I wasn't able to get anything to render.
Is this possible to do at all, or am I just wasting my time?
Edit
Stackblitz
Not sure about the customization of MTableEditField, But you can try some thing like following by writing own component.
1) The main idea is split the words (raw and suggestion) and keep them separate span elements so that we can get full control of the styling.
2) Wrap the span elements in div and write the own onChange event handlers.
PS: this is sample code, Will need to fine tune the code.
Check out the working sample on stackblitz
import React, { useState } from "react";
const dict = ['apple', 'mango', 'berry'];
const CustomTableEditField = props => {
const [rawValue, setRawValue] = useState("");
const [suggestedValue, setSuggestedValue] = useState("");
const handleKeyPress = (event) => {
// console.log('key: ', event.key);
let new_raw;
if (event.key === "Backspace") {
new_raw = rawValue.slice(0, rawValue.length - 1);
} else {
new_raw = `${rawValue}${event.key}`;
}
setRawValue(new_raw);
const suggested = dict.find(word => word.startsWith(new_raw));
if (suggested && new_raw) {
setSuggestedValue(suggested.slice(new_raw.length));
} else {
setSuggestedValue("");
}
}
return (
<div
tabIndex="0"
onKeyDown={handleKeyPress}
style={{border: '1px solid green', height: '30px', color: 'black'}}>
<span>{rawValue}</span>
{suggestedValue && (
<span
style={{backgroundColor: "#557D92",
color: "white",
padding: "offset"}}> {suggestedValue} </span>
)}
</div>
);
};
export default CustomTableEditField;

Creating re-orderable card component in React

I'm currently working my way through React, and I'm building a portfolio site. On the work page, I have 3 tiles, which will eventually be overlapping. When a card is clicked, it opens a side panel, and (hopefully) the active card goes to the front, pushing the others behind it to fill in the space.
I currently have the cards, or tabs working, I just need help with how to rearrange them on click.
This is the Tab.js component
import PropTypes from 'prop-types';
class Tab extends Component {
onClick = () => {
const { label, onClick } = this.props;
console.log('that tickles', {onClick})
onClick(label);
}
render() {
const {
onClick,
props: {
activeTab,
label,
position,
inactivePosition,
style
},
} = this;
console.log(this)
let className = 'tab-list-item';
if (activeTab === label) {
className += ' tab-list-active';
}
return (
<div
style={style}
className={className}
onClick={onClick}
>
{label}
</div>
);
}
}
export default Tab;
The tabs.js component that brings things together
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import './tabstyle.css'
import Tab from './tab.js';
class Tabs extends Component {
static propTypes = {
children: PropTypes.instanceOf(Array).isRequired,
}
constructor(props) {
super(props);
this.state = {
activeTab: this.props.children[0].props.label,
};
}
onClickTabItem = (tab) => {
this.setState({
activeTab: tab
});
}
render() {
const {
onClickTabItem,
props: {
children,
position,
},
state: {
activeTab,
inactiveTab1,
inactiveTab2,
}
} = this;
return (
<React.Fragment>
{children.map((child) => {
const { label } = child.props;
return (
<Tab
activeTab={activeTab}
key={label}
label={label}
onClick={onClickTabItem}
/>
);
})}
<div className="tab-content">
{children.map((child) => {
if (child.props.label !== activeTab) return undefined;
return child.props.children;
})}
</div>
</React.Fragment>
);
}
}
export default Tabs;
the actual work page
export default function Work() {
return (
<React.Fragment >
<Tabs>
<div label="Example1" position='1'>
what in the world
</div>
<div label="Example2" position='2'>
lorem ipsum
</div>
<div label="Example3" position='3'>
Nothing to see here, this tab is!
</div>
</Tabs>
</React.Fragment>
);
}
}
.tab-list-item {
background-color:#fff;
position: relative;
transition: all .5s;
}
.tab-content {
color: #fff;
background-color: rgb(19, 47, 74);
grid-area:1/13/span 9/ span 8;
z-index: 5;
padding:3em;
}
.tab-list-active {
background-color: #f0f;
grid-area: 2/3/span 4/ span 4;
}
.position2{
grid-area:3/4/span 4/ span 4;
}
.position3{
grid-area:4/5/span 4/ span 4;
}
In my mind, I pictured building an array, and simply having the first card be active, then when another card is clicked, that card is sent to position 0, and so on.
I hope that's everything. As I said, I'm pretty new to React, bit less new to vanilla JavaScript, but still pretty green. Any guidance would be massively appreciated, as I'm at a bit of an impasse at the moment.
For a working demo, I'm using AWS Amplify to host it temporarily https://master.d2wqg4b36m462q.amplifyapp.com/work

How to add classNames in conditional rendering in reactjs?

I have a list of data with images. I want to make image carousel. For this I have created card component and I want here to display 4 cards at a time and remaining should be hidden. Then i want to setTimeout of 5s to display remaining but only for at a time.
So far I have done this.
about.js
import './about.scss';
import data from '../../data/data';
import CardSection from './card';
class About extends React.Component{
constructor(props){
super(props);
this.state = {
properties: data.properties,
property: data.properties[0]
}
}
nextProperty = () => {
const newIndex = this.state.property.index+4;
this.setState({
property: data.properties[newIndex]
})
}
prevProperty = () => {
const newIndex = this.state.property.index-4;
this.setState({
property: data.properties[newIndex]
})
}
render() {
const {property, properties} = this.state;
return (
<div className="section about__wrapper">
<div>
<button
onClick={() => this.nextProperty()}
disabled={property.index === data.properties.length-1}
>Next</button>
<button
onClick={() => this.prevProperty()}
disabled={property.index === 0}
>Prev</button>
<Container className="card__container">
<div class="card__main" style={{
'transform': `translateX(-${property.index*(100/properties.length)}%)`
}}>
{
this.state.properties.map(property => (
<CardSection property={property}/>
))
}
</div>
</Container>
</div>
</div>
)
}
}
export default About
about.scss
.card__container{
overflow-x: hidden;
}
.card__main{
display: flex;
position: absolute;
transition: transform 300ms cubic-bezier(0.455, 0.03, 0.515, 0.955);
.card__wrapper {
padding: 20px;
flex: 1;
min-width: 300px;
}
}
card.js
import React from "react";
import { Card, CardImg, CardText, CardBody,
CardTitle, CardSubtitle, Button } from 'reactstrap';
class CardSection extends React.Component {
render() {
return (
<div className="card__wrapper">
<Card>
<CardImg top width="100%" src={this.props.property.picture} alt="Card image cap" />
<CardBody>
<CardTitle>{this.props.property.city}</CardTitle>
<CardSubtitle>{this.props.property.address}</CardSubtitle>
<CardText>Some quick example text to build on the card title and make up the bulk of the card's content.</CardText>
<Button>Button</Button>
</CardBody>
</Card>
</div>
);
}
}
export default CardSection;
I have added transition in them to change card onclick but i want them to auto change and hide the remaining card.
Right now it looks like this,
You can add items in componentDidMount method using setInterval
componentDidMount() {
this.interval = setInterval(() => this.setState({
properties:data.properties /* add your data*/ }), 4000);
}
componentWillUnmount() {
clearInterval(this.interval);
}
You can have a property called showCardIds that holds an array of the Id of cards that need to be shown, and use that to set a Boolean property called hidden on the div of the card.
You could also do something like this as shown in the example below, this example also uses showCardIds as a state. It filters only for the property that needs to be rendered and filters out the rest.
Here is an example:
...
{
this.state.properties.filter((property, index) => showCardIds.includes(index)).map(property => (
<CardSection property={property}/>
))
}
...
That way only the ones that are present in the array of showCardIds would show up, there needs to be more logic to be written that would populate the ids in showCardIds
Hope this helps. The hidden property is supported from HTML5, and should work on most browsers, unless they are truly "ancient".

Categories