I am quite new in react and just struggling a bit to make it work properly.
So here is a snippet from JS file and I need to convert it react.
let squares = document.getElementsByClassName("square");
for (let i = 0; i < squares.length; i++) {
squares[i].addEventListener("mouseenter", () => {
squares[i].classList.add("light");
setTimeout(function () {
squares[i].classList.remove("light");
}, 800);
});
}
In that react component I have just some divs with className="square"
export default function SomeComponent() {
return (
<div className="row ">
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
<div className="square"></div>
</div>
);
}
Create a component for each square.
Return a JSX div from it.
Create a state in that component for light (default it to false).
If light is true, add the class to the list of class names for the div (the classnames module is helpful here).
Add a onMouseOver function which sets the state of light to true.
Add a useEffect hook which depends on the value of light. Inside that hook, use setTimeout to change the state back to false after the time period.
holo, may you can check this?
and this is online demo
constructor(props) {
super(props);
this.state = {
name: 'React',
currentIndx: undefined,
doms: Array.from({length: 10}).fill(1)
};
}
handleMouse = (index: number) => {
this.setState({
currentIndx: index
});
setTimeout(() => {
this.setState({
currentIndx: undefined
})
}, 1000)
}
render() {
const { doms, currentIndx } = this.state;
return (
<div>
<Hello name={this.state.name} />
<p>
Start editing to see some magic happen :)
</p>
<div>
{doms.map((item, index) => (<div onMouseEnter={() => this.handleMouse(index)} className={`square ${currentIndx === index ? 'light': ''}`} key={index}>{index}</div>))}
</div>
</div>
);
}
The easiest way to do it would be something like this
import React, { useState } from "react";
const ListItem = () => {
const [hovered, setHovered] = useState(false);
return (
<div
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
className={`square ${hovered ? 'light' : ''}`}
/>
);
}
const List = () => {
return (
<div className="row">
<ListItem />
<ListItem />
<ListItem />
<ListItem />
<ListItem />
<ListItem />
<ListItem />
<ListItem />
<ListItem />
<ListItem />
</div>
);
}
Create a Square component first;
import React, { useState } from "react";
import "./Square.css";
export const Square = () => {
const [light, setLight] = useState(false);
const mouseOver = () => {
setLight(!light);
};
return (
<div onMouseOver={mouseOver} className={light ? "light" : null}>
Square
</div>
);
};
export default Square;
Then on your page; import it and use it
import React from 'react'
import './App.css'
import Square from './components/Square'
function App() {
return (
<div className="container">
{Array(3)
.fill(' ')
.map((item) => {
return (
<tr>
<td className="space">
<Square />
</td>
<td className="space">
<Square />
</td>
<td className="space">
<Square />
</td>
</tr>
)
})}
</div>
)
}
export default App
When you mouseOver to the square component it will turn on red, if u do it again, className will be null so it will change back to normal color easy tutorial for you
CSS
.space{
padding: 5px;
}
.light{
color: red
}
Related
I do not understand the problem. I am trying to make an app where the user is given a list of reviews and when they click on one, they are redirected to a page that shows details of that single review. Here is my ReviewCard.js file:
import React from 'react';
import { reviews } from '../data';
import StarRatings from 'react-star-ratings';
import './Review.css';
const ReviewCard= ({ review }) => {
return (
<div class="card-deck">
{reviews.map((review) => {
return (
<div class="card">
<div key={review.id}>
<h4 class="card-title">{review.place}</h4>
<StarRatings
rating={review.rating}
starRatedColor="gold"
starDimension="20px"
/>
<div class="card-body">{review.content}</div>
<div class="card-footer">{review.author} - {review.published_at}</div>
</div>
</div>
);
})}
</div>
);
};
export default ReviewCard;
and my ReviewCollection.js file:
import React from 'react';
import ReviewCard from './ReviewCard';
class ReviewCollection extends React.Component {
goToDetails = (review) => {
localStorage.setReview('selectedReview', review);
this.props.history.push('/details');
};
render() {
return (
<div onClick={() => this.goToDetails(review)}>
<div className='card-collection'>
{this.props.reviews.data
.filter((review, idx) => idx < 24)
.map((review) => (
<ReviewCard key={review.id} review={review}
/>
))}
</div>
</div>
)
}
}
export default ReviewCollection;
I am receiving an error from the Review Collection component saying that "Review" is not defined. I do not understand why this is happening.
<div onClick={() => this.goToDetails(review)}> Here, you are sending review but its not defined anywhere.
I think you need to include your onClick function inside the .map() function
{this.props.reviews.data
.filter((review, idx) => idx < 24)
.map((review) => (
<div onClick={() => this.goToDetails(review)}>
<ReviewCard key={review.id} review={review} />
</div>
))}
import React from 'react';
import ReviewCard from './ReviewCard';
import { reviews } from '../data';
import {reactLocalStorage} from 'reactjs-localstorage';
import { browserHistory } from 'react-router';
class ReviewCollection extends React.Component {
goToDetails = (review) => {
reactLocalStorage.set('selectedReview', review);
browserHistory.push('/details');
};
render() {
return (
<div className='card-collection'>
{reviews
.filter((review, idx) => idx < 24)
.map((review) => (
<div onClick={() => this.goToDetails(review)}>
<ReviewCard key={review.id} review={review} />
</div>
))}
</div>
)
}
}
export default ReviewCollection;
This is my App.jsx:
import React from 'react';
import SoltM from './slot';
const App = ()=>{
return(
<>
<div>
<SlotM x="emoji1" y="emoji1" z="emoji1" />
<hr />
<SlotM x="emoji2" y="emoji3" z="emoji3" />
<hr />
<SlotM x="emoji3" y="emoji3" z="emoji3" />
<hr />
</div>
</>
)
}
export default App;
This is my SlotM.jsx component, in this, props are not displayed in True or False component.
import React from 'react';
const SlotM = (props) => {
return ( (props.x === props.y && props.y === props.z) )}
const True = (props) => {
let { x, y, z } = props
return (
<>
<div className="slot_inner">
<h1> {x} {y} {z} </h1>
<h1> This is Matching </h1>
</div>
</>
)
}
const False = (props) => {
let { x, y, z } = props
return (
<>
<div className="slot_inner">
<h1> {x} {y} {z} </h1>
<h1> This is not Matching. emoji1 </h1>
</div>
</>
)
}
export default SlotM;
This is my app.jsx
2:This is SlotM.jsx component in this props are not being displayed in True and False component
You can use spread operator like this:
<True {...props} /> <False {...props} />
I think you misunderstood sth. props.x === props.y && props.y === props.z) ) returns boolean value, not Function. How about this?
const SlotM = (props) => {
return (props.x === props.y && props.y === props.z) ? <TrueC {...props}/>: <FalseC {...props}/>
}
const TrueC = (props) => {
...
const FalseC = (props) => {
...
I am in the progress of learning React. I want to show countries' information via the toggleable button. But I have some problem with that.
There is an input box that is triggered by entering letters. I send HTTP Get Request depends on this input and the response is being filtered. The value which is filtered appears on the screen.
Ass you see, I just want the country name and button to appear. After that, when I press the button, only information about that country should come.
My code:
App.js
import React from 'react'
import Countries from './components/Countries'
const App = () => {
return (
<div>
<Countries />
</div>
)
}
export default App
Countries.js
import React, { useState,useEffect} from 'react'
import ShowSection from './ShowSection'
import axios from 'axios'
const Countries = (props) => {
const [search,setSearch] = useState('')
const [countries,setCountries] = useState([])
useEffect(()=> {
axios
.get('https://restcountries.eu/rest/v2/all')
.then((response) => {
console.log("Burda")
const responseCountries = response.data
const filter = responseCountries.filter(el =>
el.name.toLowerCase()
.indexOf(search.toLocaleLowerCase()) > -1)
setCountries(filter)
})
},[search])
const handleInput = (event) => {
setSearch(event.target.value)
console.log(countries)
}
return(
<div>
find countries <input onChange={handleInput}/>
<div>
<ShowSection list={countries}/>
</div>
</div>
)
}
export default Countries
ShowSection.js
import React from 'react'
import InfoSection from './InfoSection'
const ShowSection = (props) => {
const {list} = props
var id = 0;
if(list.length === 1){
return(
<div>
{
list.map((item,index) =>
<div>
<h2>{item.name}</h2>
<p>capital {item.capital}</p>
<p>population {item.population}</p>
<h3>languages</h3>
<ul>
{item.languages.map(m =>
<li key={index.toString()}>{m.name}</li>)}
</ul>
<img alt="Flag" src={item.flag} width="150px" height="150px"/>
</div>
)
}
</div>
)
}
else if(list.length <= 10){
return(
list.map((item,i) =>
<div>
<InfoSection key={item.id} item={item} num={++id}/>
</div>
)
)
}
else{
return(
<div>Nothing to rendered</div>
)
}
}
export default ShowSection
InfoSection.js
import React,{useState} from 'react'
const InfoSection = (props) => {
const {item} = props
const [toggle,setToggle] = useState(false)
return(
<div>
{item.name}
<button onClick={() =>setToggle(!toggle)}>
{toggle ? 'Cancel' : 'Show'}
</button>
<p>capital {item.capital}</p>
<p>population {item.population}</p>
<h3>languages</h3>
<ul>
{item.languages.map(m =>
<li key={item.callingCodes}>{m.name}</li>)}
</ul>
<img alt="Flag" src={item.flag} width="150px" height="150px"/>
</div>
)
}
export default InfoSection
Like #GG mentioned in the comments, you can use conditional rendering to display the details of the country when toggle is true/false.
Like this
return(
<div>
{item.name}
<button onClick={() =>setToggle(!toggle)}>
{toggle ? 'Cancel' : 'Show'}
</button>
{toggle &&
<>
<p>capital {item.capital}</p>
<p>population {item.population}</p>
<h3>languages</h3>
<ul>
{item.languages.map(m =>
<li key={item.callingCodes}>{m.name}</li>)}
</ul>
<img alt="Flag" src={item.flag} width="150px" height="150px"/>
</>
}
</div>
)
I have a list of Child objects mapped from my Parent component in my React App.
When a Child item is clicked, I need the props.name of that item to be pushed to the selectedItems array in the Parent component via the handleClick function.
How can I achieve this?
function Parent() {
let selectedItems = [];
const result = Data.filter((e) => selectedItems.includes(e.id));
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{Data.map((item, i) => {
return <Child
key={item.id}
name={item.name} />
})}
</main>
</div>
);
}
export default App
const Child = (props) => {
const [clickCount, setClickCount] = useState(0);
function handleClick() {
setClickCount(prevClickCount => prevClickCount + 1);
}
return (
<div
className="product"
onClick={() => handleClick()}
>
<p>{props.name}</p>
<p>{clickCount > 0 ? <p>Selected: {clickCount}</p> : <p>Not Selected</p>}</p>
<img src={props.img} alt="" />
</div>
);
}
I would recommend using hooks for the 'selectedItems' in the parent component, as to trigger a re-render when the name changes.
You can pass functions from the parent to the child component using props.
Below I've passed the 'addToSelectedItems' function down to the child and triggered it in the handleClick method.
const Parent = () => {
const [selectedItems, setSelectedItems] = useState([]);
function addToSelectedItems(name){
setSelectedItems([...selectedItems, name]);
}
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{Data.map((item, i) => {
return <Child
key={item.id}
name={item.name}
addToSelectedItems={addToSelectedItems}
/>
})}
</main>
</div>
);
}
export default App
const Child = (props) => {
const [clickCount, setClickCount] = useState(0);
function handleClick(name) {
setClickCount(prevClickCount => prevClickCount + 1);
props.addToSelectedItems(name);
}
return (
<div
className="product"
onClick={(props.name) => handleClick(props.name)}
>
<p>{props.name}</p>
<p>{clickCount > 0 ? <p>Selected: {clickCount}</p> : <p>Not Selected</p>}</p>
<img src={props.img} alt="" />
</div>
);
}
I'd do something like this, but I have not tested it, it might need some fine tuning
function Parent() {
let selectedItems = [];
const result = Data.filter((e) => selectedItems.includes(e.id));
const [clickCount, setClickCount] = useState(0);
function handleClick(name) {
setClickCount(prevClickCount => prevClickCount + 1);
selectedItem.push(name)
}
return (
<div className="App">
<main className="products-grid flex flex-wrap">
{Data.map((item, i) => {
return <Child
key={item.id}
name={item.name}
clickCount={clickCount}
handleClick={handleClick} />
})}
</main>
</div>
);
}
export default App;
const Child = (props) => {
let { handleClick, name, clickCount, img } = props
return (
<div
className="product"
onClick={() => handleClick(name)}
>
<p>{name}</p>
<p>{clickCount > 0 ? <p>Selected: {clickCount}</p> : <p>Not Selected</p>}</p>
<img src={img} alt="" />
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I'm trying to develop a fairly simplistic E-Mail template creator with React JS. I'm using the "react-sortable-hoc" library as a means to handle the ordering of elements on the page.
The goal is to allow users to create "Rows", rearrange rows, and within each row, have multiple "Columns" that can contain components like images, textboxes, etc...
But I keep running into the same issue with Sortable libraries. Form fields cannot maintain their own "state" when being dragged up or down. The State of a Component in React JS seems to be lost when it's in a draggable component. I've experienced similar issues with JQuery UI's Sortable but it required an equally ridiculous solution. Is it common to find that form fields are simply super difficult to rearrange?
As a "proof of concept", I am using a complex JSON object that stores all the information in the Letter.js component and passes it down as Props which are then passed down to each component. But as you can tell, this is becoming cumbersome.
Here is an example of my Letter component that handles the JSON object and sorting of Rows:
import React, {Component} from 'react';
import {render} from 'react-dom';
import {
SortableContainer,
SortableElement,
arrayMove
} from 'react-sortable-hoc';
import Row from './Row';
const SortableItem = SortableElement(({row, rowIndex, onChange, addPart}) => {
return (
<li>
<Row
row={row}
rowIndex={rowIndex}
onChange={onChange}
addPart={addPart} />
</li>
)
});
const SortableList = SortableContainer(({rows, onChange, addPart}) => {
return (
<ul id="sortableList">
{rows.map((row, index) => {
return (
<SortableItem
key={`row-${index}`}
index={index}
row={row}
rowIndex={index}
onChange={onChange}
addPart={addPart}
/> )
})}
</ul>
);
});
class Letter extends Component {
constructor(props) {
super(props);
this.state = {
rows: [],
}
this.onSortEnd = this.onSortEnd.bind(this);
this.onChange = this.onChange.bind(this);
this.addRow = this.addRow.bind(this);
this.addPart = this.addPart.bind(this);
}
addPart(event, index, value, rowIndex, columnIndex) {
console.log(value);
var part = {};
if(value === 'Text') {
part = {
type: 'Text',
value: ''
}
} else if(value === 'Image') {
part = {
type: 'Image',
value: ''
}
} else {
part = {
type: 'Empty',
}
}
const { rows } = this.state;
rows[rowIndex][columnIndex] = part;
this.setState({ rows: rows })
}
onChange(text, rowIndex, columnIndex) {
const { rows } = this.state;
const newRows = [...rows];
newRows[rowIndex][columnIndex].value = text;
this.setState({ rows: newRows });
}
addRow(columnCount) {
var rows = this.state.rows.slice();
var row = [];
for(var i = 0; i < columnCount; i++) {
var part = {
type: 'Empty',
}
row.push(part);
}
rows.push(row);
this.setState({ rows: rows })
}
onSortEnd = ({oldIndex, newIndex}) => {
this.setState({
rows: arrayMove(this.state.rows, oldIndex, newIndex),
});
};
render() {
console.log(JSON.stringify(this.state.rows));
const SideBar = (
<div className="sideBar">
<h3>Add a Row</h3>
<button className="uw-button" onClick={() => this.addRow(1)}>1 - Column</button><br/><br/>
<button className="uw-button" onClick={() => this.addRow(2)}>2 - Column</button><br/><br/>
<button className="uw-button" onClick={() => this.addRow(3)}>3 - Column</button>
<hr />
</div>
);
if(this.state.rows.length <= 0) {
return (
<div className="grid">
<p>This E-Mail is currently empty! Add some components to make a template.</p>
{SideBar}
</div>
)
}
return (
<div className="grid">
<SortableList
rows={this.state.rows}
onChange={this.onChange}
addPart={this.addPart}
lockAxis="y"
useDragHandle={true}
onSortStart={this.onSortStart}
onSortMove={this.onSortMove}
onSortEnd={this.onSortEnd}
shouldCancelStart={this.shouldCancelStart} />
{SideBar}
</div>
);
}
}
export default Letter;
And here is an example of Row:
import React, { Component } from 'react';
import { Text, Image } from './components/';
import { SortableHandle } from 'react-sortable-hoc';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import { Card, CardActions, CardHeader, CardMedia, CardTitle, CardText } from 'material-ui/Card';
import DropDownMenu from 'material-ui/DropDownMenu';
import MenuItem from 'material-ui/MenuItem';
const DragHandle = SortableHandle(() => <span className="dragHandle"></span>);
class Row extends Component {
constructor(props) {
super(props);
}
render() {
if(this.props.row !== undefined && this.props.row.length > 0) {
const row = this.props.row.map((column, columnIndex) => {
if(column.type === 'Empty') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="emptyColumn">
<Card>
<DragHandle />
<CardTitle title="Empty Component"/>
<DropDownMenu value={"Empty"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
</Card>
</div>
</MuiThemeProvider>
)
} else if(column.type === 'Text') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="textColumn">
<Card>
<DragHandle />
<CardTitle title="Textbox"/>
<DropDownMenu value={"Text"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
<Text
value={this.props.row[columnIndex].value}
onChange={this.props.onChange}
columnIndex={columnIndex}
rowIndex={this.props.rowIndex} />
</Card>
</div>
</MuiThemeProvider>
)
} else if(column.type === 'Image') {
return (
<MuiThemeProvider key={columnIndex}>
<div className="textColumn">
<Card>
<DragHandle />
<CardTitle title="Image"/>
<DropDownMenu value={"Image"} onChange={(event, index, value) => this.props.addPart(event, index, value, this.props.rowIndex, columnIndex)}>
<MenuItem value={"Empty"} primaryText="Empty" />
<MenuItem value={"Text"} primaryText="Textbox" />
<MenuItem value={"Image"} primaryText="Image" />
</DropDownMenu>
<Image
columnIndex={columnIndex}
rowIndex={this.props.rowIndex} />
</Card>
</div>
</MuiThemeProvider>
)
}
})
return (
<div className="row">
{row}
</div>
)
}
return <p>No components</p>;
}
}
export default Row;
Lastly, this is what Text.js looks like
import React, { Component } from 'react';
import ReactQuill from 'react-quill';
class Text extends Component {
constructor(props) {
super(props);
}
render() {
return (
<ReactQuill value={this.props.value}
onChange={(text) => this.props.onChange(text, this.props.rowIndex, this.props.columnIndex)} />
)
}
}
export default Text;
So, I keep having to pass ridiculous parameters to onChange functions and other functions in order to ensure that the state is maintained while sorting and editing. So, how should I be handling this? I don't want Letter.js (which is basically App.js) to handle all of my data handling. I want each component to handle it's own. I want Text.js to handle the onChange effects of its text. But I just can't see a way around passing everything down as props.