React.js+Bootstrap rendering rows - javascript

I am using bootstrap and I want to render 4 columns in row. However I do not know how many columns I will have, so it should work for any number of columns and also first column can be different react component then other columns.
What I want to achieve:
<div class="row">
<div class="col-md-3 component-type-1">...</div>
<div class="col-md-3 component-type-2">...</div>
<div class="col-md-3 component-type-2">...</div>
<div class="col-md-3 component-type-2">...</div>
</div>
<div class="row">
<div class="col-md-3 component-type-2">...</div>
<div class="col-md-3 component-type-2">...</div>
<div class="col-md-3 component-type-2">...</div>
<div class="col-md-3 component-type-2">...</div>
</div>
I tried something but did not managed to achieve what I want..
import chunk from 'lodash/chunk.js'
class Test extends React.Component {
render() {
let component1=null;
if (this.state.shouldBeComponent1) {
component1=<Component1 key="component1" />;
}
let items = [];
if (component1!=null) items.push(component1);
this.state.dataForComponents2.forEach((data) => {
items.push(<Component2 key={data.ID} />)
});
const rows = chunk(items, 4);
let pageBody=null;
if (items.length>0) {
pageBody=(
rows.map((row) => {
<div className="row">
{
row.map((item) => (
{item}
))
}
</div>})
);
}
return (
<div>
<div className="header">
///Other unreleated code
</div>
{pageBody}
</div>
);
}

Seems something wrong with your pageBody
Try this.
let pageBody= [];
if (items.length>0) {
rows.forEach((row, idx) => {
pageBody.push
(
<div key={idx} className="row">
{row}
</div>
)}
);
}
And example here

Related

React - Show/hide when mouse hovers using hooks

I'm trying to create a show/hide div for when my mouse enters and leaves the container. I was following this example here (https://upmostly.com/tutorials/react-onhover-event-handling-with-examples) but I've run into a problem when I hover my mouse over the 'delete-container' div, it disappears. This problem occurs because it takes the action onMouseLeave. Is there a way I can fix this or possibly make my solution better? Here is a demo of what is happening (https://i.gyazo.com/528d909625b6b3828325c4e62894d1c3.mp4).
import React, { useState } from 'react';
import axios from 'axios';
export default function JobInfo({ jobs_info }) {
const [isShown, setIsShown] = useState(false);
const changeBackground = (x) => {
x.target.style.backgroundImage =
'linear-gradient(to right, #4639a7, #78019c)';
};
const changeBackground2 = (x) => {
x.target.style.background = 'rgb(37, 45, 73)';
};
return (
<div className='row'>
<div
className='container'
onMouseEnter={() => setIsShown(true)}
onMouseLeave={() => setIsShown(false)}
>
<div className='row'>
<div className='job-title'>{jobs_info.title}</div>
</div>
<div className='row wrapper'>
<div className='category-title'>Category</div>
<div className='location-title'>Location</div>
<div className='type-title'>Type of Job</div>
<div className='creator-title'>Job Creator</div>
</div>
<div className='row wrapper'>
<div className='category'>{jobs_info.job_team.title}</div>
<div className='location'>
{jobs_info.job_location.title}
</div>
<div className='type'>{jobs_info.job_work_type.title}</div>
<div className='creator'>{jobs_info.user.name}</div>
</div>
</div>
<div
className='counter-container'
id='counter-container'
onMouseEnter={changeBackground}
onMouseLeave={changeBackground2}
>
Candidates <br />
{jobs_info.candidates_count}
</div>
{isShown && (
<div className='delete-container center'>
<ion-icon id='trash' name='trash'></ion-icon>
</div>
)}
</div>
);
}
The issue happens because delete-container is outside of the container hierarchy and hence mouseleave event is triggered on the container. Render the delete-container as a child of container and style it accordingly
return (
<div className='row'>
<div
className='container'
onMouseEnter={() => setIsShown(true)}
onMouseLeave={() => setIsShown(false)}
>
<div className='row'>
<div className='job-title'>{jobs_info.title}</div>
</div>
<div className='row wrapper'>
<div className='category-title'>Category</div>
<div className='location-title'>Location</div>
<div className='type-title'>Type of Job</div>
<div className='creator-title'>Job Creator</div>
</div>
<div className='row wrapper'>
<div className='category'>{jobs_info.job_team.title}</div>
<div className='location'>
{jobs_info.job_location.title}
</div>
<div className='type'>{jobs_info.job_work_type.title}</div>
<div className='creator'>{jobs_info.user.name}</div>
</div>
{isShown && (
<div className='delete-container center'>
<ion-icon id='trash' name='trash'></ion-icon>
</div>
)}
</div>
<div
className='counter-container'
id='counter-container'
onMouseEnter={changeBackground}
onMouseLeave={changeBackground2}
>
Candidates <br />
{jobs_info.candidates_count}
</div>
</div>
);
However you could simply use CSS hover event to show or hide the delete-container without the need for state after renderingdelete-containeras a child ofcontainer`
.scss
.container {
.delete-container {
display: none;
// other styles
}
&:hover {
.delete-container {
display: block;
}
}
// other styles
}

React.js - Close and add another row div after X items

I'm learning React.js.
I have this code:
const articles = Object
.keys(this.state.articles)
.map(key => <ArticleThumb key={key} details={this.state.articles[key]} />)
;
return (
<div className="container">
<div className="row">
{ articles }
</div>
</div>
)
Assuming I have 6 items, here is the code after rendering:
<div className="container">
<div className="row">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
<div id="item4"></div>
<div id="item5"></div>
<div id="item6"></div>
</div>
</div>
But I want to have only 3 items per line like this:
<div className="container">
<div className="row">
<div id="item1"></div>
<div id="item2"></div>
<div id="item3"></div>
</div>
<div className="row">
<div id="item4"></div>
<div id="item5"></div>
<div id="item6"></div>
</div>
</div>
What is the best way to do this?
The easy answer is to use something like lodash's chunk function https://lodash.com/docs/4.17.4#chunk
However, if you are not using npm and or do not want to add additional dependencies you are going to have to use a good old fashioned javascript for loop to perform the grouping you need.
With the markup you have you could do it via css:
.container {
display: flex;
flex-wrap: wrap;
}
.row {
width: 33%;
box-sizing: border-box;
}
I made a ArticleGrid component:
class ArticleGrid extends Component {
render() {
let articlesRows = Object
.keys(this.props.rows)
.map(key => <ArticleRow key={key} articles={this.props.rows[key]} />)
;
return (
<div id="articles" className="container">
{articlesRows}
</div>
);
}
}
export default ArticleGrid;
A ArticleRow component:
class ArticleRow extends Component {
render() {
let articles = Object
.keys(this.props.articles)
.map(key => <ArticleThumb key={key} details={this.props.articles[key]} />)
;
return (
<div className="row">
{articles}
</div>
);
}
}
export default ArticleRow;
I used lodash's chunk and values function (ty Deadron) and it's done:
let articles = _.values(this.state.articles);
let articlesRows = _.chunk(articles, 3);
return (<ArticleGrid rows={articlesRows} />);

Sort array onClick and render the array in React

I have an array full of objects that I fetched and I am trying to sort the array onClick of an arrow in React. I have a sort function that works perfect in javascript but I am new to React and can't figure out how to implement the function and render the list again.
I am getting errors messages of all sorts depending on what I try. Anything from cannot sort undefined to 'expecting onclick to be a function instead of an object like in this case.
var LeaderBoard = React.createClass({
sortDescending: function(property) {
return function (a,b) {
return (a[property] > b[property]) ? -1 : (a[property] < b[property]) ? 1 : 0;
}
},
getInitialState: function() {
return {
data: loading
};
},
componentWillMount: function() {
fetch('https://fcctop100.herokuapp.com/api/fccusers/top/recent', {
method: 'get'
}).then(response => response.json()).then(data => {
this.setState({
data: data,
});
}).catch(function(error) {
console.log("error is ", error);
});
},
render: function() {
var information = [];
for (var j=0; j<13; j++) {
information.push(
<div className="row" key={this.state.data.username}>
<div className="col-md-1 col-xs-1">
<h4>{j+1}</h4>
</div>
<div className="col-md-4 col-xs-4">
<h4>{this.state.data[j].username}</h4>
</div>
<div className="col-md-4 col-xs-4">
<h4>{this.state.data[j].recent}</h4>
</div>
<div className="col-md-3 col-xs-3">
<h4>{this.state.data[j].alltime}</h4>
</div>
</div>
);
}
return (
<div>
<div id="Title" className="row">
<h1>freeCodeCamp Leaderboard</h1>
</div>
<div className="row">
<div className="col-md-1 col-xs-1">
<h4>#</h4>
</div>
<div className="col-md-3 col-xs-3">
<h4>Camper Name
</h4>
</div>
<div className="col-md-5 col-xs-5">
<h4>Points in past 30 days
<img className="arrow" src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-arrow-up-b-128.png" />
<img className="arrow" onClick = {this.state.data.sort(this.sortDescending("recent"))}
src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-arrow-down-b-128.png" />
</h4>
</div>
<div className="col-md-3 col-xs-3">
<h4>All time points</h4>
</div>
</div>
<div>{information}</div>
</div>
);
}
});
You are setting onClick to tbe result of a function, not tbe function itself.
Replace
`<img className="arrow" onClick={this.state.data.sort(this.sortDescending("recent"))} src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-arrow-down-b-128.png" />`
With
<img className="arrow" onClick = {() => this.state.data.sort(this.sortDescending("recent"))} src="https://cdn4.iconfinder.com/data/icons/ionicons/512/icon-arrow-down-b-128.png" />
React onClick events cannot be anything but a function, for future reference. (Also, JS refers to Arrays sometimes as Objects, which explains the error you're getting)

React onClick preinitialization

This is my React.component code. OnClick event executed on page initialization and i cant fix this, i tried 2 pull onClick over the maping, but this has no sense:
handleClick (id){
alert(id);
}
render() {
var tmp = this.handleClick;
return(
<div className="thirteen wide column">
<div className="rrc-title">Магазины, нарушающие РРЦ</div>
<div className="custom-hr"></div>
<div className="ui grid">
{
jsonResult.data.map(function(el){
return (
<div className="three wide column">
<div className="store-item-bad" onClick={tmp(el.siteId)}>
<div className="siteName">{el.siteName}</div>
{
el.values.map(function(element){
var processWidth ={
background : element.color,
width: element.percent+'%'
}
return(
<div className="BarItem">
<div className="progressBar">
<div className="ui tiny progress">
<div className="bar" style={processWidth}></div>
</div>
</div>
<div className="progressCounter">{element.count}</div>
</div>)
})
}
</div>
</div>
);
})
}
</div>
<div className="rrc-title">Магазины, соблюдающие РРЦ</div>
<div className="custom-hr"></div>
<div className="ui grid">
{
jsonResult.data.map(function(el){
return (
<div className="three wide column">
<div className="store-item-ok">
<div className="siteName">{el.siteName}</div>
{
el.values.map(function(element){
var processWidth ={
background : element.color,
width: element.percent+'%'
}
return(
<div className="BarItem">
<div className="progressBar BarFloatingLeft">
<div className="ui tiny progress">
<div className="bar" style={processWidth}></div>
</div>
</div>
<div className="progressCounter">{element.count}</div>
</div>)
})
}
</div>
</div>
);
})
}
</div></div>
);
}
It's easy thing, but i can't focus right now, so i need ur help guys:)
Try:
onClick={this.handleClick.bind(this,el.siteId)} or
onClick={tmp.bind(this,el.siteId)}
And add arrow func in map:
map(e=>{})

How to show loader in reactjs and meteor?

I have a page where 3 recipes are listed along with more button. When more button is clicked more 3 recipes are listed. What i am trying to do is before listing more 3 recipes i want to show a spinner/loader icon but i could only change the text of button. How can i show loader icon as soon as more button is clicked and before those additional 3 recipes are listed. I am using meteorjs and reactjs.
my code for this is
export default class Home extends Component {
constructor(){
super();
this.state = { limit:3 , loading:false }
this.addMore = this.addMore.bind(this);
}
getMeteorData(){
let data = {};
data.recipes = [];
data.recipes = Recipes.find({},{sort:{createdAt:-1}}).fetch();
let recipeHandle = Meteor.subscribe('recipelist',this.state.limit);
if(recipeHandle.ready()){
data.recipes = Recipes.find({},{sort:{createdAt:-1},limit:this.state.limit}).fetch();
}
return data;
}
addMore(){
this.setState({
limit:this.state.limit + 3, loading: true }, () => {
this.setTimeout(()=>{
this.setState({loading:false});
},2000);
});
}
render() {
console.log('this.data.recipes',this.data.recipes);
let recipes = _.map(this.data.recipes,(recipe) => {
return <RecipeList key={recipe._id} recipe={recipe} loading={this.state.loading} />
});
return (
<div className="row">
<div className="intro blink z-depth-1">
<div className="row">
<div className="col l7">
<h1 className="heading flow-text blink">Sell your Recipe</h1>
</div>
</div>
</div>
<div className="row">
<div className="col s12">
{recipes}
</div>
</div>
<button onClick={this.addMore} type="button" className="btn coral more">More</button>
</div>
);
}
}
ReactMixin(Home.prototype, ReactMeteorData);
You could remove the loading state, and just compute the loading state from the data: {this.state.limit !== this.data.recipes.length && <img src="path_to_loader.gif" />}
I am not sure where you want to show the loader, but for example you could do:
render() {
console.log('this.data.recipes',this.data.recipes);
let recipes = _.map(this.data.recipes,(recipe) => {
return <RecipeList key={recipe._id} recipe={recipe} loading={this.state.loading} />
});
return (
<div className="row">
<div className="intro blink z-depth-1">
<div className="row">
<div className="col l7">
<h1 className="heading flow-text blink">Sell your Recipe</h1>
</div>
</div>
</div>
<div className="row">
<div className="col s12">
{recipes}
</div>
</div>
{this.state.limit !== this.data.recipes.length && <img src="path_to_loader.gif" />}
<button onClick={this.addMore} type="button" className="btn coral more">More</button>
</div>
);
}

Categories