I struggle to render a simple grid for my test project.
Didn't want to create grid by hand, because with bigger grids that would not only be a chore, but also the code would be cluttered, so figured I should use lodash for this.
However, I can't seem to render the grid, it's just not visible even when I inspect in dev tools. Can someone point my mistakes?
I am also fine with using other tools than lodash if necessary.
Here is the code:
import React from 'react';
import _ from 'lodash';
import './game.css';
const GRID = [
[{x: 1, y:3}, {x:2, y:3}, {x:3,y:3}],
[{x: 1, y:2}, {x:2, y:2}, {x:3,y:2}],
[{x: 1, y:1}, {x:2, y:1}, {x:3,y:1}],
]
class Game extends React.Component {
renderGrid() {
return _.map(GRID, row =>{
_.map(row, cell =>{
return <div style={{height: 100 + 'px', width: 100+ 'px'}}> {cell.x}, {cell.y} </div>
})
})
}
render() {
return (
<div className="game">
{this.renderGrid()}
</div>
)
}
}
export default Game;
You are not returning the inner map result, once you do that it will work
renderGrid() {
return _.map(GRID, row =>{
return _.map(row, (cell, index) =>{
return <div key={index} style={{height: 100 + 'px', width: 100+ 'px'}}> {cell.x}, {cell.y} </div>
})
})
}
Working codesandbox
In your case, the array buildin map function should be enough.
Don't forget give an unique key for each element in the map
Tips:
items.map(item => item) is the short hand format for items.map(item => { return(item); })
If you put number in inline css style, 'px' unit will be used as default.
Based on your input:
class Game extends Component {
render() {
return (
<div className="game">
{
GRID.map((row, rowIdx) => (
row.map((cell, cellIdx) => (
<div
key={`${rowIdx}-${cellIdx}`}
style={{ height: 100, width: 100 }}
>
{cell.x}, {cell.y}
</div>
))
))
}
</div>
);
}
}
There is the codesandbox demo for this code: https://codesandbox.io/s/2px4znwopr
Hope this answer could help.
Full solution to render a grid using bootstrap:
renderGrid() {
return _.map(GRID, row => {
return <div className="row"> {_.map(row, cell => {
return <div style={{ height: 100 + 'px', width: 100 + 'px' }}> {cell.x}, {cell.y} </div>
})
} </div>
})
}
Related
I'm new to StackOverflow and looking forward to contributing back to the community!
My first question, I am trying to make some squares change color on the screeen, after an onClick event. I'm nearly there, but I keep getting an error when I try to update the state, which then should updates the color. Please could you let me know what I'm doing wrong?
App.js
import React from "react"
import boxes from "./boxes"
import Box from "./Box"
export default function App() {
const [squares, setSquares] = React.useState(boxes)
function changeOn() {
console.log(squares)//just checking I'm getting the full object
setSquares({
id: 1, on: false //this was previously [...prev], on: !squares.on
})
}
const squaresElement = squares.map(props => (
<Box key={props.id} on={props.on} onClick={changeOn} />
))
return (
<main>
{squaresElement}
</main>
)
}
Box.js
import React from "react"
export default function Box (props) {
const styles= props.on ? {backgroundColor: "#222222"} : {backgroundColor: "none"}
return (
<div className="box" style={styles} onClick={props.onClick}></div>
)
}
Boxes.js
export default [
{
id: 1,
on: true
},
{
id: 2,
on: false
},
{
id: 3,
on: true
},
{
id: 4,
on: true
},
{
id: 5,
on: false
},
{
id: 6,
on: false
},
]
I hope somebody can easily spot what's wrong here?
I was expecting to see the color of the top left box change to a different color, after a click.
There are two issues:
setSquares needs the whole array, so you need to give it a new squares array
The styling back to None does not work always. better to give it the white color again
Please find the codesandbox
export default function App() {
const [squares, setSquares] = React.useState(boxes);
function changeOn(id) {
setSquares(
squares.map((square) => {
return { ...square, on: id === square.id ? !square.on : square.on };
})
);
}
const squaresElement = squares.map((props) => (
<Box key={props.id} on={props.on} onClick={() => changeOn(props.id)} />
));
return <main>{squaresElement}</main>;
}
And in Box.js
const styles = props.on
? { backgroundColor: "#222222" }
: { backgroundColor: "#fff" };
You're calling setSquares and passing it a single object instead of an array.
On the next render squares.map(...) blows up because squares is the object, and the object doesn't have a map method.
// after this call squares is just this one object
setSquares({
id: 1, on: false
})
Here's a possible implementation that pushes the on/off responsibility into the box component itself.
// generates a list of items (faking your boxes.js)
const boxes = Array.from({length: 9}, (_, id) => ({ id }));
// container element to render the list
function Boxen ({ items }) {
return (
<div className="container">
{items.map((item, idx) => (
<Box item={item} key={idx} />
))}
</div>
)
}
// component for a single box that can toggle its own on/off state
function Box ({item}) {
const [active, setActive] = React.useState();
return (
<div onClick={() => setActive(!active)} className={active ? 'active' : ''}>{item.id}</div>
)
}
ReactDOM.render(<Boxen items={boxes}/>, document.getElementById('root'));
.container {
display: grid;
grid-template-columns: repeat(3, 100px);
grid-template-rows: repeat(3, 100px);
gap: 1em;
}
.container > * {
display: flex;
justify-content: center;
align-items: center;
background: skyblue;
}
.container > .active {
background: slateblue;
color: white;
}
<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>
<div id="root"></div>
Hello I have a DataGrid with a column that has a custom header. This header is a Select.
What I want to do is every time the user selects an option the column should be sorted desc.
The renderHeader looks like this
renderHeader: (params) => {
return <CategoryPickerHeader value={category} handleChange={setCategory} />;
},
I know the DataGrid api has a couple methods for sorting (https://v4.mui.com/api/data-grid/grid-api/#main-content) sortColumn() & applySorting()
But I haven't found any example of how to use those api methods.
Can someone provide an example or knows how to use the DataGrid api?
Thanks in advance!
Visit this page, this has an example:
https://codesandbox.io/s/ugeb8?file=/demo.js
IMPORTANT : pass the arguments to property sortModel, is this answer
import * as React from 'react';
import { DataGrid } from '#mui/x-data-grid';
import { useDemoData } from '#mui/x-data-grid-generator';
export default function BasicSortingGrid() {
const { data } = useDemoData({
dataSet: 'Commodity',
rowLength: 10,
maxColumns: 6,
});
const [sortModel, setSortModel] = React.useState([
{
field: 'commodity',
sort: 'asc',
},
]);
return (
<div style={{ height: 400, width: '100%' }}>
<DataGrid
{...data}
sortModel={sortModel}
onSortModelChange={(model) => setSortModel(model)}
/>
</div>
);
}
I am trying to drag and drop any html element in nested level of container.
First level of drag and drop of elements are working but nested level is not working.
Nested level means "Dropping button inside card element which also an element".
I am taking card as control and container.
I am developing in reactjs, react-dnd.
Code :
app.js
const App = props =>{
const [controlsList, setControlList]= useState([
{ email_txt }, { button }, { card } , {textarea } ...
])
return (
<>
<div className="draggable">
{
controlsList.map(({_id, type, title}, index)=>{
<ControlsAndContainers _id={_id} type={type} title={title} />
})
}
</div>
<div className="droppable">
<DropBox/>
</div>
</>
)
}
ControlsAndContainer.js
import { useDrag } from 'react-dnd'
const ControlsAndContainer = ({_id, type, title })=>{
const [ {opacity}, drag ] = useDrag(()=>({
type,
item: { _id, type, title },
end: (item, monitor)=>{
//
},
collect: (monitor) =>({
opacity: monitor.isDragging()? 0.4 : 1
})
}), [title, type]);
const box_style = {
cursor: 'move', border: '1px dashed gray'
}
return (
<div ref={drag} style={{ ...box_style, opacity}}>
{title}
</div>
)
}
dropbox.js
import { useDrop } from 'react-dnd'
const DropBox = () =>{
let temp =[];
const [dataState, setDataState] = useState([]);
const [{isOver }, drop] = useDrop(()=> ({
accept: ['button', 'email', 'card', 'textarea'],
drop(item, monitor){
temp.push(item);
setDataState(temp);
},
collect:(monitor)=>{
isOver: monitor.isOver(),
}
}), []);
const ButtonControl = () => {
return ( <div> <button>Button</button> </div>)
}
.... email, textarea
// card code is from react-bootsrap
const CardControl = () => {
<Card style={{ width: '18rem' }}>
<Card.Header>Header</Card.Header>
<Card.Body>
Drop other element here
</Card.Body>
<Card.Footer>Footer</Card.Footer>
</Card>
}
return (
<div ref={drop}>
dataState.map((data,index)=>{
let container;
switch(data.type){
case 'button': container=<ButtonControl />
break;
case 'button': container=<CardControl />
break;
default: break;
}
return (
<> <div key={data._id}> { container } </div></>
)
})
</div>
)
}
I am trying to drag and drop button inside "Card" control which is not working but card drag and drop is working and outside the card is also working.
What I am missing ?
Please somebody help
I solved this problem. There are two ways to solve it.
create 2nd drop ref, I mean
const [, nestedDrop] = useDrop(()=>{ accept, drop, ... }));
use nestedDrop inside inner container like this ,
<Card.Body>
<div ref={nestedDrop}></div>
</Card.Body>
way is inspired from this official example :
nested drop area
you can customize nested dropbox according to your need.
I am working on a web app in the ReactJS framework and I'm using react-slideshow-image component for a simple slideshow. However due to how the component works, I can only render the images. I would like to add a short description for each image and have it appear with it. Is there a way to modify this code to render a description under the image? (I was thinking about useEffect hook but I'm not sure.)
const Slideshow = () => {
return (
<SlideContainer>
//styled component
<Zoom scale={0.4}>
//Zoom component comes from react-slideshow-image
{
slideshowImages.map((each, index) => <img key={index} style={{padding: "0", margin: "0", width: "20vw"}} src={each} />)
}
</Zoom>
</SlideContainer>
)
};
Try this behavior, Here you can show the description on the image.
const images = [
{
id: "img1",
url: "../images/image-1.png",
description: "image 1 description here"
},
{
id: "img2",
url: "../images/image-2.png",
description: "image 2 description here"
}
];
const Slideshow = () => {
return (
<div className="slide-container">
<Zoom {...zoomOutProperties}>
{images.map((each, index) => (
<div
style={{
background: `url(${each.url}) no-repeat`,
width: "300px",
height: "240px"
}}
>
<b>{each.description}</b>
</div>
))}
</Zoom>
</div>
);
};
Hope you are looking for the same use case.
Working demo:- https://codesandbox.io/s/modest-proskuriakova-28qsk?file=/src/App.js
This wasn't quite what I wanted but it pointed me in the right direction. Here's my solution inspired by yours and official React documentation:
const slideshowImages = [
{
id: 1,
image: "/imageUrl",
desc: //description
},
//as many elements as you want
]
const Slideshow = () => {
//SlideContainer and DescriptionWrapper are styled components
return (
<SlideContainer>
<Zoom {...zoomOutProperties}>
{
slideshowImages.map(
(slide) =>
<div key={slide.id}>
<img style={{padding: "0", margin: "0", width: "20vw"}} src={slide.image} />
<DescriptionWrapper>{slide.desc}</DescriptionWrapper>
</div>
)
}
</Zoom>
</SlideContainer>
)
};
export default Slideshow;
Thanks a lot, I wouldn't have thought of something like this.
I'm currently porting a very old ReactJS application to ReactJS 16 however I'm struggling on how the render function works since I don't have a React.DOM anymore.
On the old component I've got the following (I've removed unnecessary code from example):
define([
'react'
], function(
React
){
var D = React.DOM;
return React.createClass({
render: function() {
//If the Engine is not connected or the game is starting
if(this.state.engine.connectionState !== 'JOINED' || this.state.engine.gameState === 'STARTING')
return D.div({ className: 'bet-bar-starting' });
var betPercentages = calculatePlayingPercentages(this.state.engine);
var playingLostClass, cashedWonClass, mePlayingClass;
if(this.state.engine.gameState === 'ENDED') {
playingLostClass = 'bet-bar-lost';
cashedWonClass = 'bet-bar-won';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-lost': 'bet-bar-me-won';
} else {
playingLostClass = 'bet-bar-playing';
cashedWonClass = 'bet-bar-cashed';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-playing': 'bet-bar-me-cashed';
}
return D.div({ className: 'bet-bar-container' },
D.div({ className: cashedWonClass, style: { width: betPercentages.cashedWon + '%' } }),
D.div({ className: mePlayingClass, style: { width: betPercentages.me + '%' } }),
D.div({ className: cashedWonClass, style: { width: betPercentages.cashedWonAfter + '%' } }),
D.div({ className: playingLostClass, style: { width: betPercentages.playingLost + '%' } })
);
}
});
});
However I'm struggling to understand how to rewrite the render() function to the latest ReactJS version? I've managed to do the following, but I don't understand how to do the multidimensional calls to the DOM.
class BetBar extends React.Component {
render() {
if(this.state.engine.connectionState !== 'JOINED' || this.state.engine.gameState === 'STARTING')
return (<div class='bet-bar-starting'/>);
let betPercentages = calculatePlayingPercentages(this.state.engine);
let playingLostClass, cashedWonClass, mePlayingClass;
if(this.state.engine.gameState === 'ENDED') {
playingLostClass = 'bet-bar-lost';
cashedWonClass = 'bet-bar-won';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-lost': 'bet-bar-me-won';
} else {
playingLostClass = 'bet-bar-playing';
cashedWonClass = 'bet-bar-cashed';
mePlayingClass = StateLib.currentlyPlaying(this.state.engine)? 'bet-bar-me-playing': 'bet-bar-me-cashed';
}
//I don't understand how to do the D.div functions...
}
}
ReactDOM.render(<BetBar />);
The code you are looking at is from before JSX. JSX introduced a syntax which allows you to create elements without calling functions. This results in a much more declarative style, similar to HTML, which allow you to describe your components.
To translate old code -- pre JSX -- to modern day React, all you need to do is understand the function call.
D.div({ className: 'bet-bar-container' })
This creates a div with the className "bet-bar-container", in React is takes the HTML attributes as arguments and applies them to the desired DOM element for you.
<div className="bet-bar-container"></div>
So, for example with the code you have, it would roughly translate to something like this:
<div className="bet-bar-container">
<div className="cashedWonClass", style={{ width: betPercentages.cashedWon + '%' }}></div>
<div className="mePlayingClass", style={{ width: betPercentages.me + '%' }}></div>
<div className="cashedWonClass", style={{ width: betPercentages.cashedWonAfter + '%' }}></div>
<div className="playingLostClass", style={{ width: betPercentages.playingLost + '%' }}></div>
</div>