React -render values onClick of tabs - reactjs

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?

Related

Display data from API

i have the following code in parent.js file which gets data from API using axios which is working fine
//Parent.js
componentDidMount() {
axios.get('URL', {
method: 'GET',
headers: {
'key': 'apikeygoeshere'
}
})
.then((response) => {
this.success(response);
})
}
successShow(response) {
this.setState({
person: response.data.data.Table
});
}
render() {
return (
<div class="row">
{this.state.person.map(results => (
<h5>{results.first_name}</h5>
)
)
}
and the above code display data from api perfect. i want to display api data in child component instead of displaying data from json file. In child component i have the following code which display data from local.json file
//
The issue is in the successShow function the you cannot change the array state value like that. According to the answer from here :
Correct modification of state arrays in ReactJS
You can update the state like this:
this.setState(prevState => ({
person: [...prevState.person,response.data.data.Table]
});
or
this.setState({
person: this.state.person.concat([response.data.data.Table])
});
Try using
const data = this.state.person && this.state.person.find(item => item.id === id);
const relatedTo = this.state.person && this.state.person.filter( item => item.manager_id === data.manager_id && item.id !== data.id );

React state update issue (sry, can't headline it more specific) [duplicate]

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

where to insert my todo in reactJs using axios post request?

where to write axios post request to insert todo into database.If I write axios post request in componentDidUpdate() whenever click on checkbox for todo_completed status it will insert in database. duplicate record maintains fro true and false. i dont understand where to call post request in todoApp.jsx
Here is my Code
todoapp.jsx
var React = require('react');
var TodoSearch = require('TodoSearch');
var AddTodo = require('AddTodo');
var TodoList = require('TodoList');
var axios= require('axios');
var TodoApp=React.createClass({
getInitialState:function(){
return{
todo_completed:false,
strSearchText:'',
todos:[]
};
},
componentDidMount:function(){
var that=this;
axios.post('/displaytodo').then(function (response){
console.log("display");
var todos=response.data;
console.log(todos);
that.setState({
todos:response.data
});
}).catch(function (error){
console.log(error);
});
},
componentDidUpdate:function(){
var todo_text="";
var todo_completed="";
this.state.todos.forEach(function(todo){
todo_text= todo.todo_text;
todo_completed=todo.todo_completed;
});
//insert todo in database
axios.post('/addtodo',{
todo_text:todo_text,
todo_completed:todo_completed
}).then(function (response) {
console.log("data");
}).catch(function (error) {
console.log(error);
});
},
handleAddTodo:function(todo_text){
alert("new todo "+todo_text);
//insert query needed to add todo
this.setState({
todos:[
...this.state.todos,
{
todo_text:todo_text,
todo_completed:false
}
]
});
},
handleToggle:function(todo_id){
var updatedTodos=this.state.todos.map((todo)=>{
if(todo.todo_id===todo_id){
todo.todo_completed=!todo.todo_completed;
}
return todo;
});
//update query required for completed status
this.setState({
todos:updatedTodos
})
//alert(id);
},
handleSearch:function(boolShowCompleted,strSearchText){
this.setState({
boolShowCompleted:boolShowCompleted,
strSearchText:strSearchText.toLowerCase()
});
},
render:function(){
var urlValue = this.props.params.sessionValue;
console.log(urlValue);
var {todos}=this.state;
return(
<div>
{urlValue}
<TodoSearch onSearch={this.handleSearch}/>
<TodoList todos={todos} onToggle={this.handleToggle}/>
<AddTodo onAddTodo={this.handleAddTodo}/>
</div>
)
}
});
module.exports=TodoApp;
AddTodo.jsx
var AddTodo = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var strTodoText = this.refs.strTodoText.value;
if (strTodoText.length > 0) {
this.refs.strTodoText.value = '';
this.props.onAddTodo(strTodoText);
} else {
this.refs.strTodoText.focus();
}
},
render: function() {
return ( < div >
< form onSubmit = { this.handleSubmit } >
< input type = "text" ref = "strTodoText" / >
< button className = "button" > Add Todo < /button>
</form > Add todo.....
< /div>
)
}
});
You need to add an axios post request at two places,
In the handleAddTodo function, that gets called when the new todo is added. With this post request you need to insert a new entry into the table
In the handleToggle function, that gets called when you toggle the state of todo, With this post request you need to update the entry that already exist in your table

list.map not being displayed in React Component

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.

Sending row/cell data on click to the function - ReactJS

I am retrieving table data from componentWillMount and showing it as UI. I want to trigger a fuction when the row/cell is clicked and return that value back to another PHP so that i can query the backend using that retrieved cell value.
index = 0,1,2,3 ( I have 4 columns )
row = data for each index.
I am not sure why this.state.testTime is not sending the correct value to handleClick function. Does anyone have any inputs on this? Thanks.
_handleClick: function (event) {
this.setState({testTime: event.target.value});
console.log(event.target.value);
var data = {
testTime: this.state.testTime
}
console.log("clicked");
$.ajax({
type: "GET",
crossDomain: true,
url: "http://localhost:8080/TEST/capture.php",
data: data,
success: function(data){
alert(data);
},
error:function(data)
{
alert("Data sending failed");
}
});
},
return (
<tbody>
{tableData.map((row, index) => {
return (
<tr key={"row_" + index} >
{row.map((cell, index) => {
return (
<td key={"cell_" + index} onClick={this._handleClick} value={this.state.testTime} >{cell}</td>
);
})}
</tr>
);
})}
</tbody>
)
setState is an async function and it accepts a callback as the second argument that will be executed once setState is completed and the component is re-rendered. So you either need to use event.target.value directly for the data variable or put your code into the callback:
this.setState({testTime: event.target.value} ,() => {
var data = {testTime: this.state.testTime}
...
$.ajax...
});

Resources