I'm trying to get this list in the view, but this doesn't display any items
render: function() {
var list = this.state.list;
console.log('Re-rendered');
return(
<ul>
{list.map(function(object, i){
<li key='{i}'>{object}</li>
})}
</ul>
)
}
list is first set to null, but then I reload it with AJAX. This on the other hand works
<ul>
{list.map(setting => (
<li>{setting}</li>
))}
</ul>
This is my whole component as it stands:
var Setting = React.createClass({
getInitialState: function(){
return {
'list': []
}
},
getData: function(){
var that = this;
var myHeaders = new Headers();
var myInit = { method: 'GET',
headers: myHeaders,
mode: 'cors',
cache: 'default' };
fetch('/list/',myInit)
.then(function(response){
var contentType = response.headers.get("content-type");
if(contentType && contentType.indexOf("application/json") !== -1) {
return response.json().then(function(json) {
that.setState({'list':json.settings});
});
} else {
console.log("Oops, we haven't got JSON!");
}
})
.catch(function(error) {
console.log('There has been a problem with your fetch operation: ' + error.message);
});;
},
componentWillMount: function(){
this.getData();
},
render: function() {
var list = this.state.list;
return(
<ul>
{list.map(function(object, i){
<li key={i}>{object}</li>
})}
</ul>
)
}
});
You are missing your return statement
{list.map(function(object, i){
return <li key={i}>{object}</li>
})}
this works
<ul>
{list.map(setting => (
<li>{setting}</li>
))}
</ul>
because anything within () is returned automatically when using an arrow function but the previous example was using {} which requires a return statement.
When should I use `return` in es6 Arrow Functions? this will give you more context around when and when not to use a return statement with arrow functions.
Related
I tried to render a list of items by Vuejs, the code below is a simplified version of it. Basically, I need it to display data, the state and data appears in VueDevTool but not on the page.
<template>
<div>
<h1>{{this.sendersList.length}}</h1> <!-- 0 -->
<h1>{{senders.length}}</h1> <!-- 0 -->
</div>
</template>
<script>
export default{
data () {
return {
sendersList: []
}
},
created () {
this.$store.dispatch('getAllSenders', {
app_id: this.$route.params.chat_id
}).then(response => {
this.sendersList = response
})
},
computed: {
senders(){
return this.$store.getters.getAllSenders
}
}
}
</script>
Store code returns data as normal, VueDevtool can see it but I cant find away to render it on the front-end
getAllMessages(context, data){
return new Promise((resolve, reject) => {
axios.post('messages/getAllMessages', {
sender_id: data.sender_id
}).then(response => {
let payload = []
for (let index = 0; index < response.data.length; index++) {
payload.push({
message_id: response.data[index].message_id,
message_content: response.data[index].message_content,
message_type: response.data[index].message_type,
message_sentiment: response.data[index].message_sentiment,
sender_id: response.data[index].sender_id,
user_id: response.data[index].user_id,
from_sender: response.data[index].from_sender,
created_date: response.data[index].created_date,
})
}
context.commit('getAllMessages', payload)
resolve(payload)
}).catch(error => {
reject(error)
})
})
},
Try change this
<h1>{{this.sendersList.length}}</h1>
To this
<h1>{{sendersList.length}}</h1>
I'm working with reactjs and cannot seem to prevent this error when trying to display JSON data (either from file or server):
Uncaught TypeError: this.props.data.map is not a function
I've looked at:
React code throwing “TypeError: this.props.data.map is not a function”
React.js this.props.data.map() is not a function
Neither of these has helped me fix the problem. After my page loads, I can verify that this.data.props is not undefined (and does have a value equivalent to the JSON object - can call with window.foo), so it seems like it isn't loading in time when it is called by ConversationList. How do I make sure that the map method is working on the JSON data and not an undefined variable?
var converter = new Showdown.converter();
var Conversation = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="conversation panel panel-default">
<div className="panel-heading">
<h3 className="panel-title">
{this.props.id}
{this.props.last_message_snippet}
{this.props.other_user_id}
</h3>
</div>
<div className="panel-body">
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
</div>
);
}
});
var ConversationList = React.createClass({
render: function() {
window.foo = this.props.data;
var conversationNodes = this.props.data.map(function(conversation, index) {
return (
<Conversation id={conversation.id} key={index}>
last_message_snippet={conversation.last_message_snippet}
other_user_id={conversation.other_user_id}
</Conversation>
);
});
return (
<div className="conversationList">
{conversationNodes}
</div>
);
}
});
var ConversationBox = React.createClass({
loadConversationsFromServer: function() {
return $.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentDidMount: function() {
this.loadConversationsFromServer();
setInterval(this.loadConversationsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="conversationBox">
<h1>Conversations</h1>
<ConversationList data={this.state.data} />
</div>
);
}
});
$(document).on("page:change", function() {
var $content = $("#content");
if ($content.length > 0) {
React.render(
<ConversationBox url="/conversations.json" pollInterval={20000} />,
document.getElementById('content')
);
}
})
EDIT: adding sample conversations.json
Note - calling this.props.data.conversations also returns an error:
var conversationNodes = this.props.data.conversations.map...
returns the following error:
Uncaught TypeError: Cannot read property 'map' of undefined
Here is conversations.json:
{"user_has_unread_messages":false,"unread_messages_count":0,"conversations":[{"id":18768,"last_message_snippet":"Lorem ipsum","other_user_id":10193}]}
The .map function is only available on array.
It looks like data isn't in the format you are expecting it to be (it is {} but you are expecting []).
this.setState({data: data});
should be
this.setState({data: data.conversations});
Check what type "data" is being set to, and make sure that it is an array.
Modified code with a few recommendations (propType validation and clearInterval):
var converter = new Showdown.converter();
var Conversation = React.createClass({
render: function() {
var rawMarkup = converter.makeHtml(this.props.children.toString());
return (
<div className="conversation panel panel-default">
<div className="panel-heading">
<h3 className="panel-title">
{this.props.id}
{this.props.last_message_snippet}
{this.props.other_user_id}
</h3>
</div>
<div className="panel-body">
<span dangerouslySetInnerHTML={{__html: rawMarkup}} />
</div>
</div>
);
}
});
var ConversationList = React.createClass({
// Make sure this.props.data is an array
propTypes: {
data: React.PropTypes.array.isRequired
},
render: function() {
window.foo = this.props.data;
var conversationNodes = this.props.data.map(function(conversation, index) {
return (
<Conversation id={conversation.id} key={index}>
last_message_snippet={conversation.last_message_snippet}
other_user_id={conversation.other_user_id}
</Conversation>
);
});
return (
<div className="conversationList">
{conversationNodes}
</div>
);
}
});
var ConversationBox = React.createClass({
loadConversationsFromServer: function() {
return $.ajax({
url: this.props.url,
dataType: 'json',
success: function(data) {
this.setState({data: data.conversations});
}.bind(this),
error: function(xhr, status, err) {
console.error(this.props.url, status, err.toString());
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
/* Taken from
https://facebook.github.io/react/docs/reusable-components.html#mixins
clears all intervals after component is unmounted
*/
componentWillMount: function() {
this.intervals = [];
},
setInterval: function() {
this.intervals.push(setInterval.apply(null, arguments));
},
componentWillUnmount: function() {
this.intervals.map(clearInterval);
},
componentDidMount: function() {
this.loadConversationsFromServer();
this.setInterval(this.loadConversationsFromServer, this.props.pollInterval);
},
render: function() {
return (
<div className="conversationBox">
<h1>Conversations</h1>
<ConversationList data={this.state.data} />
</div>
);
}
});
$(document).on("page:change", function() {
var $content = $("#content");
if ($content.length > 0) {
React.render(
<ConversationBox url="/conversations.json" pollInterval={20000} />,
document.getElementById('content')
);
}
})
You need to create an array out of props.data, like so:
data = Array.from(props.data);
then will be able to use data.map() function
More generally, you can also convert the new data into an array and use something like concat:
var newData = this.state.data.concat([data]);
this.setState({data: newData})
This pattern is actually used in Facebook's ToDo demo app (see the section "An Application") at https://facebook.github.io/react/.
It happens because the component is rendered before the async data arrived, you should control before to render.
I resolved it in this way:
render() {
let partners = this.props && this.props.partners.length > 0 ?
this.props.partners.map(p=>
<li className = "partners" key={p.id}>
<img src={p.img} alt={p.name}/> {p.name} </li>
) : <span></span>;
return (
<div>
<ul>{partners}</ul>
</div>
);
}
Map can not resolve when the property is null/undefined, so I did a control first
this.props && this.props.partners.length > 0 ?
I had the same problem. The solution was to change the useState initial state value from string to array.
In App.js, previous useState was
const [favoriteFilms, setFavoriteFilms] = useState('');
I changed it to
const [favoriteFilms, setFavoriteFilms] = useState([]);
and the component that uses those values stopped throwing error with .map function.
Sometimes you just have to check if api call has data returned yet,
{this.props.data && (this.props.data).map(e => /* render data */)}
Create an array from props data.
let data = Array.from(props.data)
Then you can use it like this:
{ data.map((itm, index) => {
return (<span key={index}>{itm}</span>)
}}
If you're using react hooks you have to make sure that data was initialized as an array. Here's is how it must look like:
const[data, setData] = useState([])
You don't need an array to do it.
var ItemNode = this.state.data.map(function(itemData) {
return (
<ComponentName title={itemData.title} key={itemData.id} number={itemData.id}/>
);
});
You need to convert the object into an array to use the map function:
const mad = Object.values(this.props.location.state);
where this.props.location.state is the passed object into another component.
As mentioned in the accepted answer, this error is usually caused when the API returns data in a format, say object, instead of in an array.
If no existing answer here cuts it for you, you might want to convert the data you are dealing with into an array with something like:
let madeArr = Object.entries(initialApiResponse)
The resulting madeArr with will be an array of arrays.
This works fine for me whenever I encounter this error.
I had a similar error, but I was using Redux for state management.
My Error:
Uncaught TypeError: this.props.user.map is not a function
What Fixed My Error:
I wrapped my response data in an array. Therefore, I can then map through the array. Below is my solution.
const ProfileAction = () => dispatch => {
dispatch({type: STARTFETCHING})
AxiosWithAuth()
.get(`http://localhost:3333/api/users/${id here}`)
.then((res) => {
// wrapping res.data in an array like below is what solved the error
dispatch({type: FETCHEDPROFILE, payload: [res.data]})
}) .catch((error) => {
dispatch({type: FAILDFETCH, error: error})
})
}
export default ProfileAction
You should try this:
const updateNews = async()=>{
const res= await fetch('https://newsapi.org/v2/everything?q=tesla&from=2021-12-30&sortBy=publishedAt&apiKey=3453452345')
const data =await res.json();
setArticles(data)
}
Add this line.
var conversationNodes =this.props.data.map.length>0 && this.props.data.map(function(conversation, index){.......}
Here we are just checking the length of the array. If the length is more than 0, Then go for it.
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': '2',
I delete that code line in setting it to fix it
You might need to convert the objects into an array to use the map function since you are getting the JSON data in array form, I changed it to:
const [data, setData] = useState([]);
from:
const [data, setData] = useState(0);
I Hope, it might be helpful for you.
Thanks
try componentDidMount() lifecycle when fetching data
I have an app that uses axios and that render the values (eg: ID and warehouseName) using map which i put on tabs. Now I want to do is post a state on warehouseID at loadBrandTotal() from the value ID that I get in the map.
So far my code is like this
export default React.createClass({
getInitialState(){
return {
warehouseName: ""
}
},
componentWillMount(){
this.loadWarehouse();
this.loadBrandTotal();
},
loadWarehouse(){
var that = this
var url = api + 'retrieveWarehouseList';
axios.post(url,
{
warehouseName : 'NONE'
})
.then(function (response) {
console.log(response.data);
that.setState({
warehouseList : response.data.retrieveWarehouseListResult
});
})
.catch(function (response) {
console.log(response);
});
},
loadBrandTotal(){
var that = this
var url = api + 'retrieveTotalSalesPerBrand';
axios.post(url,
{
warehouseID : "None"
})
.then(function (response) {
console.log(response.data);
that.setState({
totsalesperbrand : response.data.retrieveTotalSalesPerBrandResult
});
})
.catch(function (response) {
console.log(response);
});
},
render() {
var wareName = this.state.warehouseList;
return (
<ul className="tabs tabs-transparent">
{wareName.map(function(nameoObjects) {
return (
<li className="tab">
<a href="#test1" value={nameoObjects.ID} key={nameoObjects.ID}>{nameoObjects.warehouseName}</a>
</li>
)
})}
</ul>
)}
})
Thanks a lot in advance.
I'm not 100% sure what you're wanting to do, but is it that inside the loadBrandTotal() function you want to post data you've gotten in the loadWarehouse() function? And if so, WHEN are you wanting to do this posting, as it's rendered? On a button click?
Here's an example where each list element has a button that sends the ID value the element got in the map fucntion to the loadBrandTotal() function, where it's posted (see code comments for changes):
// Give the id as an argument to loadBrandTotal
loadBrandTotal(id){
var that = this
var url = api + 'retrieveTotalSalesPerBrand';
axios.post(url,
{
// Post the ID
warehouseID : id
})
.then(function (response) {
console.log(response.data);
that.setState({
totsalesperbrand : response.data.retrieveTotalSalesPerBrandResult
});
})
.catch(function (response) {
console.log(response);
});
},
render() {
var wareName = this.state.warehouseList;
return (
<ul className="tabs tabs-transparent">
{wareName.map(function(nameoObjects) {
return (
<li className="tab">
<a href="#test1" value={nameoObjects.ID} key={nameoObjects.ID}>{nameoObjects.warehouseName}</a>
// When clicked, this button sends THIS list object's nameoObject ID to the loadBrandTotal function, where it's posted
<button onClick{() => this.loadBrandTotal(nameoObjects.ID)}>Post ID</button>
</li>
)
})}
</ul>
)}
So in that example, every list element rendered in the map function includes a button that, when clicked, sends its own nameoObject ID to the loadBrandTotal function, where it's posted and the state is set. Is that the kind of thing you're trying to do?
Apologies, I probably have all of my terminology wrong here, but I am chunking up a React app into modules and am trying to combine two modules which do the same thing and come into an issue.
Specifically, I am trying to sum up totals of both income and expenditure, and have been calling two different react classes via:
<ExpenditureTotal type={this.state.cashbook.expenditure} addTotal={this.addTotal} /> and another <IncomeTotal... which does the same).
The Class is as follows (expenditure shown, but income is the same:
/* Expenditure Running Total */
var ExpenditureTotal = React.createClass({
render: function() {
var expIds = Object.keys(this.props.expenditure);
var total = expIds.reduce((prevTotal, key) => {
var expenditure = this.props.expenditure[key];
return prevTotal + (parseFloat(expenditure.amount));
}, 0);
this.props.addTotal('expenditure', total);
return(
<h2 className="total">Total: {h.formatPrice(total)}</h2>
);
}
});
I wanted to combine the two by making it more generic, so I made the following:
/* Cashflow Running Total */
var TotalCashflow = React.createClass({
render: function() {
var expIds = Object.keys(this.props.type);
var total = expIds.reduce((prevTotal, key) => {
var type = this.props.type[key];
return prevTotal + (parseFloat(type.amount));
}, 0);
this.props.addTotal('type', total);
return(
<h2 className="total">Total: {h.formatPrice(total)}</h2>
);
}
});
The only reason it doesn't work properly is when I add the summed total to the relevant state object which for this is income or expenditure in totals: (totals: { income: val, expenditure: val}).
Where I was previously explicitly specifying 'expenditure' or 'income' in the module, (seen above in ExpenditureTotal as this.props.addTotal('expenditure', total);, I am not sure in React how to pass the total value to the relevant place - it needs to read either 'expenditure' or 'income' to populate the correct state totals key.
Apologies if this is a bit garbled, struggling to explain it clearly.
Thank you :)
Update: App component in full:
import React from 'react';
// Firebase
import Rebase from 're-base';
var base = Rebase.createClass("FBURL")
import h from '../helpers';
import Expenditure from './Expenditure';
import Income from './Income';
import TotalCashflow from './TotalCashflow';
import AddForm from './AddForm';
import Available from './Available';
var App = React.createClass({
// Part of React lifecycle
getInitialState: function() {
return {
cashbook: {
expenditure: {},
income: {}
},
totals: {},
available: {}
}
},
componentDidMount: function() {
// Two way data binding
base.syncState('cashbook', {
context: this,
state: 'cashbook'
});
},
addExpenditure: function(expenditure) {
var timestamp = (new Date()).getTime();
// update state object
this.state.cashbook.expenditure['expenditure-' + timestamp] = expenditure;
// set state
this.setState({
cashbook: { expenditure: this.state.cashbook.expenditure }
});
},
addIncome: function(income) {
var timestamp = (new Date()).getTime();
// update state object
this.state.cashbook.income['income-' + timestamp] = income;
// set state
this.setState({
cashbook: { income: this.state.cashbook.income }
});
},
removeExpenditure: function(key) {
this.state.cashbook.expenditure[key] = null;
this.setState({
cashbook: { expenditure: this.state.cashbook.expenditure }
});
},
renderExpenditure: function(key) {
var details = this.state.cashbook.expenditure[key];
return(
<tr className="item" key={key}>
<td><strong>{details.name}</strong></td>
<td><strong>{h.formatPrice(details.amount)}</strong></td>
<td>{details.category}</td>
<td>{details.type}</td>
<td>{details.date}</td>
<td><button className="remove-item" onClick={this.removeExpenditure.bind(null, key)}>Remove</button></td>
</tr>
);
},
removeIncome: function(key) {
this.state.cashbook.income[key] = null;
this.setState({
cashbook: { income: this.state.cashbook.income }
});
},
renderIncome: function(key) {
var details = this.state.cashbook.income[key];
return(
<tr className="item" key={key}>
<td><strong>{details.name}</strong></td>
<td><strong>{h.formatPrice(details.amount)}</strong></td>
<td>{details.category}</td>
<td>{details.type}</td>
<td>{details.date}</td>
<td><button className="remove-item" onClick={this.removeIncome.bind(null, key)}>Remove</button></td>
</tr>
);
},
listInventory: function() {
return
},
addTotal: function(type, total) {
this.state.totals[type] = total;
},
render: function() {
return(
<div className="cashbook">
<Expenditure
cashbook={this.state.cashbook.expenditure}
renderExpenditure={this.renderExpenditure} />
<TotalCashflow
type={this.state.cashbook.expenditure}
addTotal={this.addTotal}
identifier='expenditure'
/>
<AddForm addCashflow={this.addExpenditure} />
<Income
cashbook={this.state.cashbook.income}
renderIncome={this.renderIncome} />
<TotalCashflow
type={this.state.cashbook.income}
addTotal={this.addTotal}
identifier='income'
/>
<AddForm addCashflow={this.addIncome} />
<Available totals={this.state.totals} />
</div>
);
}
});
export default App;
If I got you correctly, you want to have a component, that renders the totals of 'expenditure' and/or 'income'. Notice, you should not modify the state within the render function, as these will trigger over and over again, with each state change it is invoking itself.
Instead, try to compute the necessary data from within the parent components componentDidMount/componentDidUpdate, so that the TotalCashflow can be served the data, without it needing to do any more logic on it.
This might be the parent component:
/* Cashflow-Wrapper */
var TotalCashflowWrapper = React.createClass({
componentDidMount: function(){
this.setState({
income: this.addTotal(/*x1*/)
expenditure: this.addTotal(/*x1*/)
});
/*x1: hand over the relevant 'type' data that you use in the child components in your example*/
}
addTotal: function(type) {
var expIds = Object.keys(type);
return expIds.reduce((prevTotal, key) => {
var x = type[key];
return prevTotal + (parseFloat(x.amount));
}, 0);
}
render: function() {
return(
<div>
<TotalCashflow total={this.state.expenditure}/>
<TotalCashflow total={this.state.income}/>
</div>
);
}
});
This would be your total component:
/* Cashflow Running Total */
var TotalCashflow = React.createClass({
render: function() {
return(
<h2 className="total">Total: {h.formatPrice(this.props.total)}</h2>
);
}
});
Edit
There are a few issues with your App component, but first of all, here is how you could redesign/simplify it. You should also move the markup from renderExpenditure and renderIncome to your Income/Expenditure components. I've been using ES6, as I've noticed you're already using arrow functions.
var App = React.createClass({
getInitialState: function () {
return {
cashbook: {
expenditure: {},
income: {}
},
totals: {},
available: {}
}
},
componentDidMount: function () {
// Two way data binding
base.syncState('cashbook', {
context: this,
state: 'cashbook'
}).then(()=> {
// after syncing cashbook, calculate totals
this.setState({
totals: {
income: this.getTotal(this.state.cashbook.income),
expenditure: this.getTotal(this.state.cashbook.expenditure),
}
});
});
},
// Get total of obj income/expenditure
getTotal: function (obj) {
var expIds = Object.keys(obj);
return expIds.reduce((prevTotal, key) => {
var type = obj[key];
return prevTotal + (parseFloat(type.amount));
}, 0);
},
addCashflow: function (identifier, amount) {
var timestamp = (new Date()).getTime();
// clone cashbook and clone cashbook[identifier] and set cashbook[identifier][identifier + '-' + timestamp] to amount
var cashbook = {
...this.state.cashbook,
[identifier]: {
...this.state.cashbook[identifier],
[identifier + '-' + timestamp]: amount
}
};
// set state
this.setState({
cashbook: cashbook,
// Update totals
totals: {
...this.state.totals,
[identifier]: this.getTotal(cashbook[identifier])
}
});
},
removeCashflow: function (identifier, key) {
// clone cashbook and clone cashbook[identifier]
var cashbook = {...this.state.cashbook, [identifier]: {...this.state.cashbook[identifier]}};
delete cashbook[identifier][key];
this.setState({
cashbook: cashbook,
totals: {
...this.state.totals,
// Update totals
[identifier]: this.getTotal(cashbook[identifier])
}
});
},
render: function () {
return (
<div className="cashbook">
<Expenditure cashbook={this.state.cashbook.expenditure} removeCashflow={(key)=>this.removeCashflow('expenditure', key)}/>
<TotalCashflow total={this.state.cashbook.expenditure} identifier='expenditure'/>
{/*or drop TotalCashflow and do <h2 className="total">Total: {h.formatPrice(this.state.totals.expandature)}</h2>*/}
<AddForm addCashflow={(amount)=>this.addCashflow('expenditure', amount)}/>
<Income cashbook={this.state.cashbook.income} removeCashflow={(key)=>this.removeCashflow('income', key)}/>
<TotalCashflow type={this.state.cashbook.income} identifier='income' />
<AddForm addCashflow={(amount)=>this.addCashflow('income', amount)}/>
<Available totals={this.state.totals}/>
</div>
);
}
});
export default App;
Issues with your current App component
Issue: You are not removing the key, you're just setting it to null; this could lead to exceptions when iterating Object.keys() and you're expecting the values to be numbers, like when calculating the totals
removeIncome: function(key) {
// this.state.cashbook.income[key] = null;
delete this.state.cashbook.income[key]
this.setState({
cashbook: { income: this.state.cashbook.income }
});
},
Bad design: You're defining the markup of a child component within your parent component, although it seems unnecessary
renderExpenditure: function(key) {
var details = this.state.cashbook.expenditure[key];
return(
<tr className="item" key={key}>
<td><strong>{details.name}</strong></td>
<td><strong>{h.formatPrice(details.amount)}</strong></td>
<td>{details.category}</td>
<td>{details.type}</td>
<td>{details.date}</td>
<td><button className="remove-item" onClick={this.removeExpenditure.bind(null, key)}>Remove</button></td>
</tr>
);
},
This could easily be moved to your Expenditure/Income component.
Issues: Mutating state, Overwriting cashbook in state and loosing expenditure/income
addExpenditure: function(expenditure) {
var timestamp = (new Date()).getTime();
// You are mutating the state here, better clone the object and change the clone, then assign the cloned
this.state.cashbook.expenditure['expenditure-' + timestamp] = expenditure;
// You are overwriting cashbook with an object, that only contains expenditure, thus loosing other properties like income
this.setState({
cashbook: { expenditure: this.state.cashbook.expenditure }
});
}
// Fixed
addExpenditure: function(expenditure) {
var timestamp = (new Date()).getTime();
// clone object
var cashbook = Object.assign({}, this.state.cashbook);
cashbook.expenditure = Object.assign({}, cashbook.expenditure);
// define latest expenditure
cashbook.expenditure['expenditure-' + timestamp] = expenditure;
// set state
this.setState({
cashbook: cashbook
});
}
// ES6
addExpenditure: function(expenditure) {
var timestamp = (new Date()).getTime();
this.setState({
cashbook: {
...this.state.cashbook,
expenditure: {
...this.state.cashbook.expenditure,
['expenditure-' + timestamp]: expenditure
}
}
});
}
You would be better off, if you'd flatten your state and cashbook object
so instead of
this.state = {
cashbook: {
expenditure: {},
income: {}
},
totals: {},
available: {}
}
having
this.state = {
expenditure: {},
income: {}
totals: {},
available: {}
}
so you could just
addExpenditure: function(expenditure) {
var timestamp = (new Date()).getTime();
var exp = Object.assign({}, this.state.cashbook.expenditure);
exp['expenditure-' + timestamp] = expenditure;
this.setState({
expenditure: exp
});
}
or es6
addExpenditure: function(expenditure) {
var timestamp = (new Date()).getTime();
this.setState({
expenditure: {
...this.state.cashbook.expenditure,
['expenditure-' + timestamp]: expenditure
}
});
}
of course you'd need to update the rebase binding and your models, dunno if this is something you want
componentDidMount: function() {
base.syncState('expenditure', {
context: this,
state: 'expenditure'
});
base.syncState('income', {
context: this,
state: 'income'
});
}
I am working with ReactJS and I am trying to get the children from this.props.children however, it is returning undefined. According to the documentation I should have access to this special property.
componentDidMount: function() {
console.log("this",this) // this ReactCompositeComponent.createClass.Constructor
this.setMenuListeners.apply(this);
this.loadMenuFromServer();
},
setMenuListeners: function() {
pubSub.on('mainMenu.menuItemClicked',function() {
console.log(this.props.children) // undefined
}.bind(this))
},
And here is some of the code that is rendering the children:
loadMenuFromServer: function() {
var menus = []
$.getJSON(APPFS.menuItems,function(data){
for(var s in data) {
menus.push(<MenuItem expandable={true} content={s} />)
menus.push(<ul onClick={this.menuItemClicked} className="main-menu-submenu">{
this.loopAndAddMenu(data[s]).map(function(result){
return(result)
})
}</ul>)
}
this.setState({data:menus})
}.bind(this));
},
loopAndAddMenu: function(data) {
var menus = []
for(var s in data) {
menus.push(<MenuItem expandable={false} content={s} key={data[s]} />)
}
return menus
},
render: function(){
return (
<ul className="main-menu">
{this.state.data}
</ul>
)
}