usestate to move component on page to a different area when clicked - javascript

I have some code:
//Top row holding one card
const Top = (props) => {
return (
<div>
<div className='row'>
<Card />
</div>
</div>
)
}
export default top;
//Bottom row of cards
const Heroes = (props) => {
return (
<div>
<p>Select a hero</p>
<div className="row">
<Card cardSize={'little-card'} hero={'Spiderman'}/>
<Card cardSize={'little-card'} hero={'Batman'}/>
<Card cardSize={'little-card'} hero={'Superman'}/>
</div>
</div>
)
}
export default Heroes;
Each card component contains a superhero. The hero prop sets the image and also serves as an identifier. There is an empty space above.
When you click one, it should move from its place to the container above, like so:
Then it when clicked again while at the top, it should move back to its original place:
Can someone dumb this down for me or show me how to do this? Code examples would be greatly appreciated.

You can add useState for checking which card gets selected, and then pass that state handling selectCard to Card component
const Heroes = (props) => {
const [selectedCard, setSelectedCard] = useState()
const selectCard = (heroName) => { setSelectedCard(heroName) }
return (
<div>
<p>Selected hero: {selectedCard}</p>
<p>Select a hero</p>
<div className="row">
<Card cardSize={'little-card'} hero={'Spiderman'} selectCard={selectCard}/>
<Card cardSize={'little-card'} hero={'Batman'} selectCard={selectCard}/>
<Card cardSize={'little-card'} hero={'Superman'} selectCard={selectCard}/>
</div>
</div>
)
}
export default Heroes;
After that, modifying your Card component like below
const Card = (props) => {
return <div onClick={() => { props.selectCard(props.hero) }}>{props.hero}</div>
}

Related

Hey how do I convert this JS into react?

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
}

React.js how to update reset my navbar when changing url?

I have created a navbar with items but I cannot find a way to reset the navbar when changing of URL.
NAV-item.jsx (this is where I can click on the button to make my navbar appear or disappear)
function NavItem (props) {
const [open,setOpen] = useState(false);
return(
<li className='nav-item'>
<a
className='icon-button'
onClick= {() => setOpen(!open)}>
{props.icon}
</a>
{open && props.children}
</li>
)
}
Directory.jsx (where my links are I tried to do history.push but I received an undefined error)
class Directory extends React.Component {
constructor(){
super();
this.state = {
Page1: PagesPrimaire,
Page2: PagesSecondaire
};
}
render() {
return(
<div className='menu-item'>
{
this.state.Page1.map(({id,title,linkUrl,history,match}) =>(
<Link key={id}
className='menu-item'
//to={`${linkUrl}`}
onClick = {() => history.push(this.state.Page1.linkUrl)}
>{title}</Link>
)
)
}
</div>
)
}
}
export default withRouter(Directory);
DropdownMenu.jsx (my navbar and some CSStransition tricks)
function DropdownMenu () {
const [activeMenu, setActiveMenu] = useState('main');
const DropdownItem = (props) =>
(
<a
className='menu-item'
onClick={()=>props.goToMenu && setActiveMenu(props.goToMenu)}>
{props.children}
</a>
)
return (
<div className='dropdown'>
<CSSTransition
in={activeMenu === 'main' }
unmountOnExit
timeout={500}
classNames='menu-primary'
>
<div className='menu'>
<Directory/>
<DropdownItem goToMenu='connexion'>Devenir Membre/connexion</DropdownItem>
</div>
</CSSTransition>
<CSSTransition
in={activeMenu === 'connexion' }
unmountOnExit
timeout={500}
classNames='menu-secondary'
>
<div className='menu'>
<DropdownItem goToMenu='main'><img src={Leftarrow} className='arrow' alt=''></img></DropdownItem>
</div>
</CSSTransition>
</div>
)
}
export default DropdownMenu;
Right now I can make the navbar appear and disappear by clicking a button but I cannot make it disappear when I change of Url.
Thank a lot,
as #kritiz enter a navabar for each of the route and navigate to the one you need or use the same one and use props to decide what to do there is not other way as far as I know.
the only two version I know is:
1.outside of switch
2.inside of each component with props to decied what to do in the nav

How do I clear the the array of a state?

So this is my code :
import React from "react";
import Navigation from './Navigation';
import Foot from './Foot';
import MovieCard from './MovieCard';
class Favorites extends React.Component {
render() {
const { onSearch, favorites, favoriteCallback, totalFavorites, searchKeyUpdate } = this.props;
return (
<div>
<Navigation
onSearch={onSearch}
totalFavorites={totalFavorites}
searchKeyUpdate={searchKeyUpdate} />
<div className="container">
<button onClick={()=> this.clearFavorites(favorites)}> Clear all movies </button>
{(favorites.length < 1) ?
<h1 style={{ fontSize: '13px', textAlign: 'center' }}>Please mark some of the movies as favorites!</h1>
:
<ul
className="movies">
{favorites
.map(movie => (
<MovieCard
movie={movie}
key={movie.imdbID}
toggleFavorite={favoriteCallback}
favorites={favorites}
/>
))}
</ul>
}
<Foot />
</div>
</div>
);
}
}
const clearFavorites = (favorites) => {
this.setState({ favorites: [] });
}
The thing I need for the button to do is that when i click it that it clears the whole state of favorites. The clearFavorites function is used to clear everything but when I try this I get an error:
Why doesn't this clear the state of favorites?
You have two problems:
clearFavorites function is not in your class. So you should put it inside.
You are trying to clear the data inside the favorites array, which is not part of your state, using the function clearFavorites. So, first of all, you should add favorites array to your state and then you can manipulate the information. I suggest you to use the function getDerivedStateFromProps.
As others mentioned, first moving clearFavorites function into Favorites class.
Second, your favorites list is not part of state object, but instead you pull it out from this.props.favorites, so instead of using this.setState, we should just change the props value.
Third, since you're emptying the array, the parameter in your clearFavorites probably not needed? Please refer to below:
First we define a constructor to get the value from props and pass it to state in the constructor as below:
constructor(props) {
super(props);
this.state = {favorites: this.props.favorites}
}
clearFavorites = () => {
this.setState({favorites: []});
};
Then at last in your render method change to following:
const { onSearch, favoriteCallback, totalFavorites, searchKeyUpdate } = this.props;
const favorites = this.state.favorites;// Or in your ul tag, instead of using favorites, change it to this.state.favorites
You can try to move the clearFavorites into your component
import React from "react";
import Navigation from "./Navigation";
import Foot from "./Foot";
import MovieCard from "./MovieCard";
class Favorites extends React.Component {
render() {
const {
onSearch,
favorites,
favoriteCallback,
totalFavorites,
searchKeyUpdate
} = this.props;
return (
<div>
<Navigation
onSearch={onSearch}
totalFavorites={totalFavorites}
searchKeyUpdate={searchKeyUpdate}
/>
<div className="container">
<button onClick={() => this.clearFavorites(favorites)}>
{" "}
Clear all movies{" "}
</button>
{favorites.length < 1 ? (
<h1 style={{ fontSize: "13px", textAlign: "center" }}>
Please mark some of the movies as favorites!
</h1>
) : (
<ul className="movies">
{favorites.map(movie => (
<MovieCard
movie={movie}
key={movie.imdbID}
toggleFavorite={favoriteCallback}
favorites={favorites}
/>
))}
</ul>
)}
<Foot />
</div>
</div>
);
}
clearFavorites = favorites => {
this.setState({ favorites: [] });
};
}
<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>

How re-render just copmonent to which I clicked - react

I'm trying to make a simple color memory game in React (find where there are two identical images).
When I click on one card all of the other cards re-render. How can I prevent this?
//app class
handleClick = index => {
this.setState((prevState) => {
var temp = [...prevState.clickedPicture, index]
return{clickedPicture: temp}
})
}
isClicked = (index) => this.state.clickedPicture.indexOf(index) === -1
render() {
return(
<div className="content">
<div className="header">
<h1>Memory</h1>
</div>
<div className="main">
_.shuffle(this.state.colors).map((current,index) =>
<Game
key={index}
index={index}
current={current}
status={this.state.status}
handleClick={this.handleClick}
bool={this.isClicked(index)}
/>)
</div>
}
// Game component
class Game extends Component {
clickHandle = () => {
if(this.props.bool){
this.props.handleClick(this.props.index)
}
}
render() {
return(
<div className={this.props.status}
style={{ backgroundColor: this.props.bool ?
'black' : this.props.current }}
onClick={this.clickHandle}>
</div>
);
}
}
Make Cards their own component so they have access to lifecycle hooks. then
make the Cards a PureComponents, therefore they will only update if the reference to a prop changes.

React DnD drags whole list of cards instead of single card

I am trying to use react DnD in my react Project. In my render method I define a variable named Populate like show below, which returns a list of cards like this
render() {
var isDragging = this.props.isDragging;
var connectDragSource = this.props.connectDragSource;
var Populate = this.props.mediaFiles.map((value) => {
return(
<div>
<MuiThemeProvider>
<Card style= {{marginBottom: 2, opacity: isDragging ? 0 : 1}} id={value.id} key={value.id}
onMouseOver={this.onMouseOver}
onMouseOut={this.onMouseOut}
//onTouchTap={() => {this.handleClick(value.id)}}
zDepth={this.state.shadow}>
<CardHeader
title={value.Episode_Name}
//subtitle={value.description}
actAsExpander={false}
showExpandableButton={false}
/>
</Card>
</MuiThemeProvider>
</div>
)
});
And my return of render method looks like this
return connectDragSource (
<div>
<MuiThemeProvider>
<div className="mediaFilesComponent2">
{Populate}
</div>
</MuiThemeProvider>
</div>
)
Problem is when I try using drag, then the whole list of cards gets selected for drag. I want all the cards having individual drag functionality.
If you want each card to have drag functionality than you'll have to wrap each card in a DragSource, and not the entire list. I would split out the Card into it's own component, wrapped in a DragSource, like this:
import React, { Component, PropTypes } from 'react';
import { ItemTypes } from './Constants';
import { DragSource } from 'react-dnd';
const CardSource = {
beginDrag: function (props) {
return {};
}
};
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
isDragging: monitor.isDragging()
}
}
class CardDragContainer extends React.Component {
render() {
return this.props.connectDragSource(
<div>
<Card style= {{marginBottom: 2, opacity: this.props.isDragging ? 0 : 1}} id={value.id} key={value.id}
onMouseOver={this.props.onMouseOver}
onMouseOut={this.props.onMouseOut}
zDepth={this.props.shadow}>
<CardHeader
title={props.title}
actAsExpander={false}
showExpandableButton={false}
/>
</Card>
</div>
)
}
}
export default DragSource(ItemTypes.<Your Item Type>, CardSource, collect)(CardDragContainer);
Then you would use this DragContainer in render of the higher level component like this:
render() {
var Populate = this.props.mediaFiles.map((value) => {
return(
<div>
<MuiThemeProvider>
<CardDragContainer
value={value}
onMouseOver={this.onMouseOver}
onMouseOut={this.onMouseOut}
shadow={this.state.shadow}
/>
</MuiThemeProvider>
</div>
)
});
return (
<div>
<MuiThemeProvider>
<div className="mediaFilesComponent2">
{Populate}
</div>
</MuiThemeProvider>
</div>
);
}
That should give you a list of Cards, each of which will be individually draggable.

Categories

Resources