The goal is to pull in the nested array "records". My current output displays the array within the react console, but with an error. I will try and be as concise as possible but will keep things short.
The error screen has 3 lines that are referencing _getRecords so im positive that _getRecords is the problem child.
class RecordBox extends Component {
constructor() {
super();
this.state = {
showComments: false,
results: []
};
}
render(){
const records = this._getRecords();
return (
// jsx template code...
);
}
// API Call
_fetchRecords() {
$.ajax({
method: 'GET',
url: 'http://apidata:8888/data.json',
success: (results) => {
this.setState({ results });
},
error: () => {
console.log('error');
}
});
}
_getRecords() {
// TypeError: this.state.results.map is not a function...
return this.state.results.map((record) => {
return <Comment body={record["Contractor Name"]} />
});
}
}
I have a feed that looks like the below. I do not have permission to modify this.
{
"result": {
"records": [
{
"id": 1,
"email": "clu.hey#gmail.com",
"author": "Clu",
"Contractor Name": "Just say no to love!!",
"avatarUrl": "https://placeimg.com/200/240/any"
},{
"id": 2,
"email": "hello#gmail.com",
"author": "Anne Droid",
"Contractor Name": "I wanna know what love is...",
"avatarUrl": "https://placeimg.com/200/240/any"
}
]
}
}
I think you just aren't setting the state to the right thing. Your state.results is currently an object. Just make sure when you set your state, you set state.results to results.result.records
this.setState({ results: results.result.records })
One thing you could also do is map the results directly in the jsx code and skip using the _getRecords function.
<div>
{
this.state.results.map( ( record ) => {
return <Comment />
}
}
</div>
This is the way I usually write this as it's easier for me to read, but it's personal preference.
I hope this helps!
The _fetchRecords function needs to change to:-
_fetchRecords() {
$.ajax({
method: 'GET',
url: 'http://apidata:8888/data.json',
success: (results) => {
this.setState({ results: results.result.records });
},
error: () => {
console.log('error');
}
});
}
Related
I'm trying to implement fixtures in my cypress project to avoid repeatedly sending same requests.
Command "ReadFixture" returns data from fixture file:
Cypress.Commands.add("ReadFixture", (fixtureName, firstKey, secondKey = "") => {
let fixturePath = `cypress/fixtures/${fixtureName}.json`;
if (secondKey.length === 0) {
cy.readFile(fixturePath).then(fixture => {
let dataArray = [];
let fixtureKeys = Object.keys(fixture);
fixtureKeys.forEach(key => {
let data = fixture[key][firstKey];
dataArray.push(data);
});
return cy.wrap(dataArray);
});
}
else {
cy.readFile(fixturePath).then(fixture => {
let dataArray = fixture[secondKey][firstKey];
});
return cy.wrap(dataArray);
};
});
Data is in json structure:
{
"id_0": {
"id": "id_0",
"more_data": [
"string_0"
]
},
"id_1": {
"id": "id_1",
"more_data": [
"string_1",
"string_2"
]
}
}
For some tests, only "id" is required, such test example:
it("Level 1", () => {
cy.ReadFixture("fixture_name", "id").then(urlKeys => {
urlKeys.forEach(keyUrl => {
cy.request({
method: "GET",
url: `${reqUrl}/${keyUrl}`
}).then(response => {
expect(response.status).to.be.equal(200);
});
});
});
})
Everything works as expected, however, for other tests "more_data" of single "id" is required. My approach is to read fixture twice - first get array of "id", like in "Level 1" test, then get "more_data" for each "id" in array. Example:
it("Level 2", () => {
cy.ReadFixture("fixture_name", "id").then(urlKeys => {
urlKeys.forEach(keyUrl => {
cy.ReadFixture("fixture_name", "more_data", keyUrl).then(keyData => {
cy.request({
method: "GET",
url: `${reqUrl}/${keyUrl}/more_data`
}).then(response => {
expect(response.status).to.be.equal(200);
expect(response.body.more_data).to.be.eql(keyData);
});
});
});
});
});
Problem is, when
cy.ReadFixture("fixture_name", "more_data", keyUrl)
is called, keyUrl is not defined for it and command returns array of "more_data" from all "id" because of if statement. Also, keyUrl can't be passed to request. Is it possible to go around this issue or the method I'm using is completely wrong?
try changing your else block to wrap the values inside your then callback:
else {
cy.readFile(fixturePath).then(fixture => {
let dataArray = fixture[secondKey][firstKey];
return cy.wrap(dataArray);
});
};
I am trying to parse a nested json request from my reactjs web app.
Below is the json that I received from a request.
response.data
{
"total": 2,
"offset": 1,
"limit": 987,
"staging": [
{
"id": 101,
"name": "Test Stage"
},
{
"id": 102,
"name": "Dev Stage"
},
{
"id": 103,
"name": "Prod Stage"
}
]
}
I need to parse “staging” and display the results on browser screen.
Below is the code that I am trying to parse. But, it is throwing error (SyntaxError: Unexpected token o in JSON at position 1).
export default class ItemLister extends React.Component {
state = {
persons: []
}
componentDidMount() {
axios
.get('https://xxx.yyy.zzz/xyz/zyx/', {
headers: {
'authorization':'Bearer XXXXXXXXX',
'X-Api-Key': 'XXXXXXXXXXXXXX',
},
withCredentials: true
})
.then(response => {
console.log(response.data) // it gets the correct response and printing in logs
const persons = response.data;
this.setState({ persons });
})
.catch (err => {
console.log("error")
});
}
render() {
return <ul>{this.state.persons.map(person => <li>{person.name}</li>)}</ul>
}
}
ReactDOM.render(<ItemLister />, document.getElementById('root'))
registerServiceWorker()
I couldn't find fix for it. Can someone guide me whether the parsing of such json is correct or not and how to get the parsed results and displayed on screen?
An error occurs because you're trying to parse an Object instead of a String. Simply skip JSON.parse and set result to response.data:
.then(response => {
console.log(response.data) // it gets the correct response and printing in logs
this.setState({ result: response.data });
})
And in you render:
render() {
return (
<ul>
{ this.state.result &&
this.state.result.staging &&
this.state.result.staging.map(person => <li>{person.name}</li>)
}
</ul>
);
}
How correctly to display the list received through URL in JSON?
Here is an example of a project. If I use a local variable - everything works, if I get the list, it displays an error.
constructor(props) {
super(props);
this.urlNews = "https://api.myjson.com/bins/1nrbo";
this.state = {
news: "",
links: [
{
name: "Имя 1",
url: "http://localhost:1",
use: true
},
{
name: "Имя 2",
url: "http://localhost:2",
use: false
},
{
name: "Имя 3",
url: "http://localhost:3",
use: false
}
]
};
}
getNews() {
fetch(this.urlNews)
.then(response => {
return response.json();
})
.then(json => {
this.setState({
news: json
});
console.log(this.state.news[1]);
});
}
componentDidMount() {
this.getNews();
}
render() {
const { news } = this.state;
return (
<ul>
{news.map((item, index) => <li>1</li>)}
</ul>
);
}
How right?
Because you defined initial value of news as string, define it as an array.
Write it like this:
this.state = {
news: [],
....
fetch will be a asynchronous call and you are fetching in componentDidMount that will get called after initial rendering, so before you get the response, you are trying to use map on string and that is throwing the error.
Check this snippet:
let news = '';
news.map(el => {
console.log(el);
})
You are not using map properly. map does not support object literal. Need to supply it with an array. You need to define the sate as an array and use the following render function.
this.state = {
news: [],
links: [
{
name: "Имя 1",
url: "http://localhost:1",
use: true
},
{
name: "Имя 2",
url: "http://localhost:2",
use: false
},
{
name: "Имя 3",
url: "http://localhost:3",
use: false
}
]
};
The following render function works.
render() {
return (
<ul>
{this.state.news.map(() => <li>1</li>)}
</ul>
);
}
I have an input field that collects an ID and should use that ID to find the corresponding entry. Below is what I currently have and at the bottom is what I would like to have.
I can get the contents of the file, but I can't do anything with it.
What I currently have:
// mock-data.js
{
id: "239491",
name: "Big Bird",
real: false,
type: "Animal"
}
And in my Vue file I'm using axios for my GET call
// search-file.Vue
axios.get('static/mock-data.js')
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.error(error)
})
This logs out what appears to be a giant string, because there's no syntax highlighting in the console.
What I would like to have is something like:
{
entries: [
"239491": {
id: "239491",
name: "Big Bird",
real: false,
type: "Animal"
},
"983502": {
id: "983502",
name: "Frodo",
real: false,
type: "Hobbit"
},
...
...
]
}
And my Vue code would ideally be something like:
axios.get('static/mock-data/entries/' + userInput)
.then((response) => {
console.log(response.data)
})
.catch((error) => {
console.error(error)
})
I know this isn't the proper syntax, but I can't find a solution
if you are trying to create a data for test purpose or none blocking front end development, why don't you call it directly? What I would do is f
function mockDataService() {
var mockData = {
entries: [
"239491": {
id: "239491",
name: "Big Bird",
real: false,
type: "Animal"
},
"983502": {
id: "983502",
name: "Frodo",
real: false,
type: "Hobbit"
}
]
};
return {
getMockDataById: function(id) {
//return mock data by id
}
}
}
//you can mock out axios or just create a fake promise.
function callMockData(userInput) {
return {
then: function(success, failure) {
success(mockDataService.getMockDataById(userInput))
}
}
}
I'm trying to implement a simple way to sort an array of data pulled from the server in React. The implementation I'm using shown below is probably not the best way to go about it, but I feel it should be working, but is not. It seems the sorting function is never being called, and the data is being displayed in the default order that it comes in from the server.
I'm trying to make a simple orderByRecent function reverse the order of the data, which is returned in chronological order. I know there are ways to accomplish this server-side but this is just an experiment for more complex client-side sorting.
sorting function:
orderByDate: (threads) => {
return threads.sort((a, b) => {
return Date.parse(a.date) > Date.parse(b.date)
})
},
Feed.js:
class ThreadList extends Component {
render() {
var threadNodes, sortedThreadNodes
if (this.props.data) {
var sorted = this.props.sortFunc(this.props.data)
var threadNodes = sorted.map(function (thread) {
return (
<Thread victim={ thread.victim }
date={ thread.date }
author={ thread.author }
ct={ thread.included.length }
likes={ thread.likes }
dislikes={ thread.dislikes }
id={ thread._id}
key={ thread._id }>
{ thread.text }
</Thread>
)
})
}
return (
<div className="threadList">
{ threadNodes }
</div>
)
}
}
var ThreadsBox = React.createClass({
handleThreadSubmit: function (thread) {
var threads = this.props.feed
var newThreads = threads.concat([thread])
this.setState({feed: newThreads})
$.ajax({
url: config.apiUrl + 'threads',
dataType: 'json',
type: 'POST',
data: thread,
xhrFields: {withCredentials: true},
success: function (data) {
// this.setState({feed: feed})
}.bind(this),
error: function (xhr, status, err) {
this.setState({data: threads})
console.log(this.url, status, err.toString())
}.bind(this)
})
},
// Feed nav buttons default to order by date
getInitialState: function () {
return {feed: [], sortFunc: helpers.orderByDate}
},
changeState: function (state, value) {
this.setState({[state]: value})
},
render: function () {
return (
<div className="threadsBox">
<ThreadForm friends={this.props.friends}
onThreadSubmit={ this.handleThreadSubmit }/>
<div className="feedNav">
<NavButtonList divId={"feedNav"}
eventFunc={this.changeState}
state={"sortFunc"}
buttons={buttonObs.mainNavButtons} />
</div>
<ThreadList data={ this.props.feed }
sortFunc={ this.state.sortFunc } />
</div>
)
}
})
module.exports = ThreadsBox
Here's a different approach.
Keep your threads in an object that maps threadId to the actual Thread data.
Keep a separate array that has the threadIds in the order that you want to sort them. When you sort your threads, you only change the ordering of the elements of the array.
When you want to sort the data differently, dispatch an action that will sort based on whatever constraints you have. Rendering the threads is as simple as performing a map over the array and getting the proper thread.