I have a code that displays the news of the day. I want to split my content into two parts, that is, for the first block, create a class named "news1" and for the second "news2" as shown in the picture https://ibb.co/ykv7BN4 How can i do this? here is my code
import React from 'react';
import newsStyle from './News.module.css';
export class News extends React.Component {
render() {
const resultsRender = [];
for (var i = 0; i < this.props.news.length; i += 2) {
resultsRender.push(
<div className={newsStyle.block}>
{
this.props.news.slice(i, i + 2).map((news, index) => {
return (
<div className={index % 2 === 0 ? newsStyle.leftContentNews : newsStyle.rightContentNews} key={index}>
<p className={newsStyle.newsTitle}>{news.title}</p>
</div>
);
}
)
}
</div>
);
}
return (
<div>
<div className={newsStyle.headlineSecond}>
<div className={newsStyle.Second}>
{resultsRender}
</div>
</div>
</div>
);
}
}
In this case, you would want a <div> for each column and append the news of each type to the column's div.
Related
I'm currently trying to render a kind of grid with div elements in React using a formerly very simple principle in jQuery.
using jQuery, quick and easy like this:
const $field = $('#field');
for(let row = 0; row < 5; row++) {
const $row = $('<div>').addClass('row');
for(let col = 0; col < 10; col++) {
const $col = $('div').addClass('col');
$row.append($col);
}
$field.apped($row);
}
done
in React I tried now already several approaches, without success
first of all and real basic:
const rows = [], cols = [];
for(let x = 0; x < 6; x++) {
let row = React.createElement(
"div", {className: "row"}
);
rows.push(row);
}
for(let i = 0; i < 7; i++) {
let col = React.createElement(
"div", {className: "col"}
);
cols.push(col);
}
class Grid extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<>
<h1>Some Header</h1>
<div id="board">
{rows}
{cols}
</div>
</>
)
}
}
Of course, the problem here is that the cols do not nest with the rows
Since unfortunately the innerHTML function does not exist in React - I understand the hint that there are security concerns - I first tried to nest the elements with the state using methods.
Without success and frankly it seems to me a step backwards to do something so simple (even using vanilla JS) with such effort.
I'm still convinced that something like this has to be much simpler - even in React.
So tried with something like this:
...
class Grid extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<>
<h1>Some Header</h1>
<div id="board">
{rows.map((el, i) => {
return <div className="row" dangerouslySetInnerHTML={{__html: cols.forEach(el => {return el}) }} />;
})}
</div>
</>
)
}
}
Unfortunately without success, only the row divs are rendered.
Next attempt unfortunately not either, but closer:
...
class Grid extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<>
<h1>Some Header</h1>
<div id="board">
{rows.map((el, i) => {
return <div dangerouslySetInnerHTML={{__html: cols}} />;
})}
</div>
</>
)
}
}
Outputs:
<div id="field">
<div>
[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],
[object Object]
</div>
<div> ... etc
using the "i" - index iterator from that map function to iterate thru Object.keys or Object.values with some additional logic wrapped around wont work either
and now I'm running out of ideas and can't find any suitable hints at the moment.
Does anyone know the final solution to do it this way?
Thanks a lot
Learn when to use HTML in an actual JSX environment:
...
for(let i = 0; i < 7; i++) {
let col = "<div class='col'></div>";
cols.push(col);
}
class Grid extends React.Component {
constructor(props) {
super(props);
};
render() {
return (
<>
<h1>Some header</h1>
<div id="board">
{rows.map((el, i) => {
return <div className="row" dangerouslySetInnerHTML={{__html: cols.join(" ")}} />;
})}
</div>
</>
)
}
...
Works
var array = [
['2','35'],
['80','30'],
['300','25']
]
so this is a simplified version of the array, what i am getting from an api call. Each children array's 1st value is quantity and 2nd value is price. below is my simplified state
this.state = {quantity:''}
Inside jsx what i am trying to do is conditionally render a classname called selected based upon quantity value of the state. whenever the state quantity changes. the selected class also should change accordingly.
below is my jsx
{array.map((price, index, arr) => {
if (index < arr.length -1) {
if (parseInt(arr[index+1][0]) > parseInt(this.state.quantity) && parseInt(this.state.quantity) >= parseInt(price[0])){
return (
<div className='price-box selected'>
<h3 className='price'>Tk {price[1]}</h3>
<p className='quantity'>{price[0]} or more</p>
</div>
);
} else {
return (
<div className='price-box'>
<h3 className='price'>Tk {price[1]}</h3>
<p className='quantity'>{price[0]} or more</p>
</div>
);
}
} else {
if (parseInt(this.state.quantity) >= parseInt(price[0])) {
return (
<div className='price-box selected'>
<h3 className='price'>Tk {price[1]}</h3>
<p className='quantity'>{price[0]} or more</p>
</div>
);
} else {
return (
<div className='price-box'>
<h3 className='price'>Tk {price[1]}</h3>
<p className='quantity'>{price[0]} or more</p>
</div>
);
}
}
})}
Here everything is working fine (apart from for quantity 0 and 1 all of the conditions are evaluating to false as expected.so not a single div is assigned selected class).I am 100% sure there is a shorter and better approach.
Name your data points and construct a test which satisfies all the requirements for selected. Then assign the class name if selected is true using a template literal.
{array.map((price, index, arr) => {
const stateQ = parseInt(this.state.quantity);
const dataQs = arr.map((p, i) => i === 0 ? 0 : parseInt(p[0]));
const selectedIndex = dataQs.findIndex((q, i, arr) => {
return stateQ >= q && stateQ < (arr[i+1] || stateQ + 1);
});
const selected = selectedIndex === index;
return (
<div className={`price-box ${selected && 'selected'}`}>
<h3 className='price'>Tk {price[1]}</h3>
<p className='quantity'>{price[0]} or more</p>
</div>
);
})}
Maybe something like this is what you're looking for ?
Working example on Codesandbox
class Quantity extends React.Component {
constructor(props) {
super(props);
this.state = {
quantity: "2"
};
}
render() {
const array = [["2", "35"], ["80", "30"], ["300", "25"], ["2"], ["", "3"]]; // With some errors
return (
<div>
<h1>Hello</h1>
{array.map((row) => {
const condition = this.state.quantity === row[0]; // Create your condition
if (row && row[0] && row[1])
return (
<div className={`price-box ${condition && "selected"}`}> // Called template literal, you can simply include selected if your condition is true
<h3>Quantity {row[0]}</h3>
<p>Price {row[1]}</p>
</div>
);
else return <div>Data error</div>;
})}
</div>
);
}
}
I think I have a simple question, but I can't get a solution to do this with react, I would like show results in two columns like:
item 1 | item 4
item 2 | item 5
item 3 | item 6
I tried verify if array lenght is 0 or new start column, but I can't draw a start div element without draw the end div element
I would like to do something like this:
render() {
const secondColumnStart = this.props.result.length / 2;
return <div className="row">
{this.props.result.map((item, i) =>
{ (i == 0 || i == secondColumnStart) && <div className="col-md-6"> }
item.value
{ (i == 0 || i == secondColumnStart) && </div> })}
</div>;
}
Simply map items as you usually do from one array. With that, use the CSS property "columns" to display them as described in the question above.
.container {
columns: 2 auto;
}
Assuming two column's, having col-md-6 class for row splitting.
create stateless component myRow
const myRow = ({index})=>{(<div className="col-md-6">{index}</div>)}
create array for each cols
const col1 = [],col2 = [];
this.props.result.forEach((item, i) => {
if(i%===0){
col1.push(myRow);
}else{
col2.push(myRow);
}
}
return the React element in render.
return <div className="row">
{col1}{col2}
</div>;
If you always want exactly two columns, then one option is to call map twice. Once for each half of the array:
const secondColumnStart = Math.floor(this.props.result.length / 2);
return (
<div className="row">
<div className="col-md-6">
{this.props.result.slice(0,secondColumnStart).map(item => item.value)}
</div>
<div className="col-md-6">
{this.props.result.slice(secondColumnStart).map(item => item.value)}
</div>
</div>
);
Will there always be 2 columns, regardless of how many items you have? If there are 5 items, should it display as col A -> 1,2,3. col B -> 4,5?
Use CSS to put the two columns side by side.
var halfwayPoint = Math.ceiling(this.props.result.length / 2)
var columnA = this.props.result.splice(0, halfwayPoint)
var columnB = this.props.result.splice(halfwayPoint)
render () {
return (
<div className='columnA'>
{columnA.map((item, i) => {
return (
<div>{item.value}</div>
)
})
}
</div>
<div className='columnB'>
{columnB.map((item, i) => {
return (
<div>{item.value}</div>
)
})
}
</div>
)
}
You can use the following code.
const Thingy = props => {
const gridCols = [[],[]];
const result = [10,20,30,40,50,60,70];
result.forEach( ( data,i )=>{
const comp = (
<button value={data}>{data+" "}</button>
);
const colNumber = i % 2;
gridCols[colNumber].push( comp );
} );
return (
<div className="container">
<div className="row">
<div className="col-sm">
{gridCols[0]}
</div>
<div className="col-sm">
{gridCols[1]}
</div>
</div>
</div>
)
};
// Render it
ReactDOM.render(
<Thingy title="I'm the thingy" />,
document.getElementById("react")
);
<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>
<div id="react"></div>
I also faced a similar problem where I need to show the results of an array into three columns in card.
For that I have grouped the array elements into groups as below.
arr = ['a','b','c','d',e','f'] --------> arr = [['a','b','c'],['d','e','f']]
let modified_collection=[]
if (collection.length>0) {
modified_collection = collection.reduce( (rows, key, index) =>{
return (index % 3 === 0 ? rows.push([key])
: rows[rows.length-1].push(key)) && rows;
}, []);
}
After grouping I have map the elements in the modified array as below.
modified_collection.map((row) =>
<Row>
{row.map(col => (<Col>
<Card
hoverable
style={{ width: 240, height : 480 }}
cover={<img alt="example" src={col.collection.image_url} />}
>
<Meta title={col.collection.title} description={col.collection.description} />
</Card>
</Col>))}
</Row>
)
The simplest method with few lines of code for your question is
list.map((list, index)=>{
return index % 2 === 0 ?
<Col xs={6}>
{list}
</Col>
:
<Col xs={6}>
{list}
</Col>
})
Below is a React.Component running on Meteor.js, hence the Session functions which are global.
For each div inside div#sidebar-wrapper, the same value foo or bar is passed into the methods this.isActive and this.changeTab.
<div
className={this.isActive('foo') + " tab-btn"}
onClick={this.changeTab.bind(null, 'foo')}>
<span className="title">Foo</span>
</div>
Question: Is it possible to assign this value foo or bar to the div as a variable, and pass this variable into the 2 functions? The idea is to make the code cleaner.
import React from 'react';
export default class Sidebar extends React.Component {
isActive(tabName) {
return status = Session.get('currentTab') == tabName ? "active" : "";
}
changeTab(tabName) {
Session.set('currentTab', tabName);
}
render() {
return (
<div id="sidebar-wrapper">
<div
className={this.isActive('foo') + " tab-btn"}
onClick={this.changeTab.bind(null, 'foo')}>
<span className="title">Foo</span>
</div>
<div
className={this.isActive('bar') + " tab-btn"}
onClick={this.changeTab.bind(null, 'bar')}>
<span className="title">Bar</span>
</div>
</div>
)
}
}
You can extract the div into its own reusable component, something like:
export default class InnerDiv extends React.Component {
isActive(tabName) {
return status = Session.get('currentTab') == tabName ? "active" : "";
}
changeTab(tabName) {
Session.set('currentTab', tabName);
}
render() {
var title = this.props.title;
var titleLowerCase = title.toLowerCase();
return (
<div>
className={this.isActive(titleLowerCase) + " tab-btn"}
onClick={this.changeTab.bind(null, titleLowerCase)}>
<span className="title">title</span>
</div>
)
}
}
And then change then render method of Sidebar to a way cleaner one:
render() {
return (
<div id="sidebar-wrapper">
<InnerDiv title="Foo" />
<InnerDiv title="Bar" />
</div>
)
}
I took the liberty to assume the the Session variable is a global one, and there is not issue moving the isActive and changeTab functions into the new component. If this is an issue, please tell me and I will propose another solution.
I'm having trouble with this logic since react/jsx does not allow for non closing tags to be added to an array/child component. For example with bootstrap css I want to add a row for every 4 columns.
So the logic is as follows:
Add a opening row ex: <div className="row">, then loop inside this row and every loop append a column ex: <div className="column>{this.data}</div> when the loop reaches 4 check with if(i % 4 == 0) and add a closing </div> tag while adding new row tag <div className="row">;
The code below would work in another language but in react this is not doable since we push a closing tag and a opening tag (which is invalid jsx):
generateColumns(columns) {
let newColumns = [];
columns.forEach(function(column, idx) {
newColumns.push( <div className="column"> some data </div> );
if (idx % 4 == 0) {
// Here we end the row and start a new row, works in any other language.
newColumns.push( </div> <div className="row"> );
}
});
// This array now has the proper tags for opening a row every 4th item and closing it.
return newColumns;
},
render() {
return (
<div className="row">
{this.generateColumns(this.props.columns)}
</div>
)
}
The expected output would be:
<div class="row">
<div class="column">
Some data
</div>
<div class="column">
Some more data
</div>
<div class="column">
Other data
</div>
<div class="column">
Something else
</div>
</div>
<div class="row">
<div class="column">
Some data
</div>
<div class="column">
Some more data
</div>
<div class="column">
Other data
</div>
<div class="column">
Something else
</div>
</div>
//the above would be repeated and new rows would appear every 4 columns.
render() {
const rows = array_chunk(this.props.columns, 4)
return (
{
rows.map((row) => (
<div className="row">
{
row.map((col) => (
<div className="col">{ col }</div>
))
}
</div>
))
}
)
}
An example array_chunk (I recommend that you use lodash)
module.exports = function chunks(arr, size) {
if (!Array.isArray(arr)) {
throw new TypeError('Input should be Array');
}
if (typeof size !== 'number') {
throw new TypeError('Size should be a Number');
}
var result = [];
for (var i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, size + i));
}
return result;
};
I actually just used arrays and react handled fine the rendering.
render() {
let rows = [],
cols = []
let index = 0
const totalCols = 20;
for (index; index < totalCols; index++) {
cols.push(<div class="col" key={index}/>)
if ((index + 1) % 4 == 0) {
rows.push(
<div class="row" key={index}>
{cols}
</div>
)
cols = []
}
}
return (
<div class="container">
{rows}
</div>
)
}