JSX not rendering after .map in React - reactjs

I am fetching a JSON file and trying to render the data from it. Everything shows up great when I console.log it but the JSX is not being rendered to the page. I was using forEach and read that it should be map instead but that doesn't fix my problem. Here's my code:
getPromoDetails(data) {
data = this.state.data;
Object.keys(data || {}).map(function(key) {
console.log("Promo ID: ",data[key].cm_ID)
console.log("Title: ",data[key].cm_title)
console.log("State: ",data[key].state)
console.log("Status: ",data[key].status)
console.log("Last Modified on: ",data[key].cm_lastmodified)
return
<div className="col-xs-12">
<div className="col-xs-3">
<img src={`https://link.com/thumbnail_${data[key].cm_ID}.jpg`}/>
</div>
<div className="col-xs-9">
<span className="col-xs-12"> {data[key].cm_title}</span>
<span>On: {data[key].cm_on}</span>
<span>State: {data[key].state}</span>
<span>Status: {data[key].status}</span>
<span>Last Modified: {data[key].cm_lastmodified}</span>
</div>
</div>
});
}
Any advice??

You are not returning the array that is the result of the map. You also have to make sure the JSX is on the same line as the return statement, or undefined will be returned.
getPromoDetails() {
const { data } = this.state;
return Object.keys(data || {}).map(function(key) {
return (
<div className="col-xs-12" key={key}>
<div className="col-xs-3">
<img src={`https://link.com/thumbnail_${data[key].cm_ID}.jpg`} />
</div>
<div className="col-xs-9">
<span className="col-xs-12"> {data[key].cm_title}</span>
<span>On: {data[key].cm_on}</span>
<span>State: {data[key].state}</span>
<span>Status: {data[key].status}</span>
<span>Last Modified: {data[key].cm_lastmodified}</span>
</div>
</div>
);
});
}

Related

How to get an updating value of an input field without using DOM or useState inside an array map

disCoins.map((c) => {
let subTotal;
function calcSubTotal(subAmount){
subTotal = (Number(c.current_price) * Number(subAmount));
console.log(subAmount);
return subTotal;
}
return(
<div id="calcElement">
<img id="coinImg" src={c.image} alt="Coin img"></img>
<div id="calcInfo">
<div id="calcName">{c.name}<span id="calcSymbol"> ({capitalize(c.symbol)})</span></div>
<div id="calcPrice">
${formatNumber(c.current_price)}
<span id="calcChange" className={c.price_change_percentage_24h < 0 ? "loss" : "gain"}> ({c.price_change_percentage_24h}%)</span>
</div>
</div>
<div id="x">
<span>×</span>
</div>
<div id="amountInput">
<form>
<input id="amountInputField" type="number" placeholder="Amount of Crypto Owned" defaultValue='0' onChange={calcSubTotal(Number(3))}></input>
</form>
</div>
<div id="eq">
<span>=</span>
</div>
<div id="subTot">
<span id="subTotal">${formatNumber(subTotal)}</span>
</div>
</div>
)})
How would I be able to get the value of that input field and have it change when it updates? React doesn't let me use useState and DOM gives me an error when I add the first item into the list because it reads the value as null.

State is null in React

I receive this error:
TypeError: this.state is null
Have code like this, but it does not work .... Any idea why?
I want to change the text of a label (reanalyzeButton)
Read several docs and tutorials and it seem it should work. No idea why it behaves like this.
This is inherited code I work with using React 0.13
var ProjectHeader = React.createClass({
displayName: 'ProjectHeader',
intervalId: null,
state: {
projectjson: [],
label: '',
},
componentDidMount() {
// Now we need to make it run at a specified interval
this.intervalId = setInterval(this.refresh, 1000);
this.setState({ label: '<span><i className="octicon octicon-sync" /> Project queued for analysis: <strong>{queuePosition}</strong>.</span>'});
},
refresh : function(){
if (this.state.projectjson.analysis_status == 'succeeded') {
clearInterval(this.intervalId);
this.setState({label: '<A onClick={this.analyzeProject} title="Request an analysis of the project"><i className="octicon octicon-sync"/> Check for new commits</A>'});
}
render : function(){
if (props.project.analysis_status == 'in_progress') {
//reanalyzeButton = <A onClick={this.analyzeProject} title="Request a re-analysis of the project"><i className="fa fa-refresh fa-spin" /> Analysis in progress</A>
reanalyzeButton = this.state.label
} else if ((!props.project.analyze) || props.project.analysis_priority == 0) {
//reanalyzeButton = <A onClick={this.analyzeProject} title="Request an analysis of the project"><i className="octicon octicon-sync"/> Check for new commits</A>
reanalyzeButton = this.state.label
} else {
//reanalyzeButton = <span><i className="octicon octicon-sync" /> Project queued for analysis: <strong>{queuePosition}</strong>.</span>
reanalyzeButton = this.state.label
}
return <div className="project-header" itemScope itemType="http://schema.org/Code">
<div className="row">
<div className="col-xs-12 col-sm-9">
<div className="clearfix">
{projectHeader}
</div>
</div>
<div className="col-xs-12 col-sm-3">
<span className="qc-badge">
{badge}
</span>
</div>
</div>
<div className="row">
<div className="col-xs-12">
<ul className="meta">
{fetchStatus}{projectInfo} <li>{reanalyzeButton}</li>
</ul>
<ul className="tags hidden-xs">
{tagList}
</ul>
</div>
</div>
You need to specify a getInitialState method in order to set the initial state. See here: https://reactjs.org/docs/react-without-es6.html#setting-the-initial-state

How to make this JSX code more generic to avoid code reuse in React?

I'm pretty new to react and I had a question. I have some code that populates some tabs with some info and I wanted some help creating a function that can be reused multiple times instead of reusing the same code for each tab.
<div className="box box-default">
<div className="box-header with-border">
<h3 className="box-title">Strings Info</h3>
<div className="key-details">
<dl className="dl-horizontal">
<dt>Count</dt>
<dd>{count}</dd>
<dt>Average Length</dt>
<dd>{avg_length}</dd>
</dl>
</div>
</div>
<div className="box-header with-border">
<h3 className="box-title">Strings</h3>
<div>
<pre>
{this.props.raw_strings}
</pre>
</div>
</div>
</div>
I was thinking I could create a populateTabs function that can take the count, average length, and the raw string data from the props as a parameter. The count, avg_length, and raw_strings are different for each tab as they each represent a different string type so I've been reusing this block for every tab despite only changing the 3 variables. What is the best way to cut down on the code reuse in this situation? thanks!
The code can be extracted to a component. In case some parameters are common in some cases, it can be higher-order component that accepts common parameters:
const boxHOC = (count, avg_length) => props => (
<div className="box box-default">
<div className="box-header with-border">
<h3 className="box-title">Strings Info</h3>
<div className="key-details">
<dl className="dl-horizontal">
<dt>Count</dt>
<dd>{count}</dd>
<dt>Average Length</dt>
<dd>{avg_length}</dd>
</dl>
</div>
</div>
<div className="box-header with-border">
<h3 className="box-title">Strings</h3>
<div>
<pre>
{props.raw_strings}
</pre>
</div>
</div>
</div>
);
const OneTwoBox = boxHOC(1, 2);
const ThreeFourBox = boxHOC(3, 4);
React is all about components, so rather than a normal function, you're better off extracting the common markup into a component, which can actually be a "function component" (as opposed to a "class component").
export function PopulateTab({ avgLength, count, rawStrings }) {
return (<div className="box box-default">
<div className="box-header with-border">
<h3 className="box-title">Strings Info</h3>
<div className="key-details">
<dl className="dl-horizontal">
<dt>Count</dt>
<dd>{count}</dd>
<dt>Average Length</dt>
<dd>{avgLength}</dd>
</dl>
</div>
</div>
<div className="box-header with-border">
<h3 className="box-title">Strings</h3>
<div>
<pre>
{rawStrings}
</pre>
</div>
</div>
</div>);
}
if tabsContents is an array of objects like..
const tabsContents = [
{ avgLength: 5, count: 8, rawStrings: "foo" },
{ avgLength: 6, count: 12, rawStrings: "bar" },
];
you can use PopulateTab like so..
import { PopulateTab } from "./populate-tab";
function Tabs({ tabsContents }) {
return (
<div>
{tabsContents.map(
({ avgLength, count, rawStrings }) =>
<PopulateTab avgLength={avgLength} count={count} rawStrings={rawStrings} />
)}
</div>
);
}
or, more concisely..
function Tabs({ tabsContents }) {
return (<div>{tabsContents.map(props => <PopulateTab {...props} />)}</div>);
}

React update component state from another component

I have one component as follow:
var SingleEditableModule = React.createClass({
getInitialState: function() {
return {
selected: false
};
},
show_overlay: function() {
$('.overlay').fadeIn();
},
render: function() {
var show_overlay = this.show_overlay;
return (
<div className="large-4 small-12 columns">
<h3 className="title">{this.props.data.title}</h3>
<div className="month">
<p>
{this.props.data.month}
</p>
</div>
<div className="img-holder">
<div
id={this.props.data.id}
onClick={show_overlay}
className="action_wrapper">
<span className="swap_trigger"></span>
<span className="action">
{this.props.data.action}
</span>
</div>
</div>
<h4>{this.props.data.title_description}</h4>
<p>{this.props.data.description}</p>
</div>
);
}
});
I want to assign a CSS class to this component based on "className" gained from "get_campus_id":
var Overlay = React.createClass({
close_overlay: function() {
$('.overlay').fadeOut();
},
get_campus_id: function(className) {
console.log(className);
},
render: function() {
var options = [],
get_campus_id = this.get_campus_id;
this.props.data.map(function(el, i){
options.push(<li
className={el.className}
onClick={get_campus_id.bind(null, el.className)}
key={i}>{el.location}</li>);
});
return (
<div className="overlay">
<div className="overlay-content">
<header className="clearfix">
<h3 className="float-left">Select your campus rotation</h3>
<div onClick={this.close_overlay} className="float-right close">
<span className="cancel">Cancel</span>
<span className="x">x</span>
</div>
</header>
<ul>
{options}
</ul>
<footer>
</footer>
</div>
</div>
)
}
});
"SingleEditableModule" represents an empty module which can be populated based on the value returned from "get-campus_id".
Full github url: https://github.com/WebTerminator/Hult
You cannot change the state of one component from another component. The best you can do is have both of them being children of a parent component, and then pass parameters as a prop. You can then use componentWillReceiveProps(nextProps) to intercept new props coming in (if you want to then modify a state based on that).

Looping in Render() function of ReactJS

I have an array of objects that I need to loop output on but am getting stuck. I tried using jQuery's .each() without success.
render: function() {
return (
$.each(events, function(k, e) {
<div className="event-item-wrap">
<div className="event-item" style="backgroundImage:e.Image">
<div className="event-item-date">e.Date</div>
<div className="event-item-title">e.Title</div>
<div className="event-item-price">e.Price</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
});
);
}
My array contains simple Javascript objects with keys and values. How can I render them in React?
Here is a example of how looping is usually done in Reactjs
var List = React.createClass({
render: function() {
return (
{ this.props.data.map(function(e) {
var eventStyle = {
backgroundImage:e.Image
};
return (
<div className="event-item-wrap">
<div className="event-item"style="{eventStyle}">
<div className="event-item-date">{e.Date}</div>
<div className="event-item-title">{e.Title}</div>
<div className="event-item-price">{e.Price}</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
)
})
}
);
}
});
React.render(<List data={ (Array goes here) } />, document.body);
I totally agree with Dominic Tobias answer about, forgetting about jQuery, since we won't be manipulating the dom nor do we need to. For all other helpers use native functions or _. or give (es6 a shot) but in addition to the answer given by eugene safronov. I would like to recommend not to create the loop within the return itself, for readability and also for flexibility purposes. See example and the example below.
var List = React.createClass({
render: function () {
var eventItems = this.props.data.map(function (item) {
var itemStyle = {
backgroundImage:item.Image
};
return (
<div className="event-item-wrap">
<div className="event-item"style="{itemStyle }">
<div className="event-item-date">{item.Date}</div>
<div className="event-item-title">{item.Title}</div>
<div className="event-item-price">{item.Price}</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
);
});
return (
<div className="app">
{ eventItems }
</div>
);
}
});
React.render(<List data={ (itemsArray) } />, document.body);
-- example with no data --
var List = React.createClass({
render: function () {
var eventItems;
if(_.isEmpty(this.props.data)) { // i used lodash/underscore _. for this example)
eventItems = (
<span>No items to display</span>
);
} else {
eventItems = this.props.data.map(function (item) {
var itemStyle = {
backgroundImage:item.Image
};
return (
<div className="event-item-wrap">
<div className="event-item"style="{itemStyle }">
<div className="event-item-date">{item.Date}</div>
<div className="event-item-title">{item.Title}</div>
<div className="event-item-price">{item.Price}</div>
<div className="event-item-bottom">
<div className="event-item-tags">
<ul>
<li>#professional</li>
<li>#livejazz</li>
<li>#courtet</li>
</ul>
</div>
</div>
</div>
</div>
);
});
}
return (
<div className="app">
{ eventItems }
</div>
);
}
});
React.render(<List data={ (itemsArray) } />, document.body);
it adds some extra flexibility, and readibility. I hope this helps u a bit, success with ReactJs!
(update: btw, now i used _. to check if data was empty, but u could also have checked if map returned nothing, and then show the different content, saves 1 extra function :D)

Resources