ReactJS select value from json array - reactjs

So I'm trying to get some data from my api and then select that data and send it to the other api, but I can't figure it out how to select the data.
import React, { Component } from 'react'
import Dropdown from 'react-dropdown'
import 'react-dropdown/style.css'
class Testas extends Component {
constructor(props){
super(props);
this.state = {
}
}
componentDidMount() {
const headers = {
'Authorization': 'Bearer ',''
};
fetch(`https://spiceworks/api/printserver/printers`,{ headers }
)
.then(res => res.json())
.then(json => {
this.setState({
isLoaded: true,
items: json.printers,
})
});
}
render() {
const { items } = this.state
const type = ['test', 'python', 'web', 'all']
const amount = [1,2,3,4,5,6,7,8,9,10]
return (
<div className="content">
<form>
<div className="row">
<div className="col-sm">
<div className="card">
<div className="card-body">
<h3 className="card-title">Printer Test</h3>
<Dropdown className="drop" options={this.state.items} placeholder="Pasirinkti printerį" />
<Dropdown className="drop2" options={type} placeholder="BÅ«das" />
<Dropdown className="drop2" options={amount} placeholder="Kiekis" />
Test
</div>
</div>
</div>
</div>
</form>
</div>
)
}
}
export default Testas
the data I recieve from api looks like this
{
"printers": [
"ZEB-SOFA15",
"ZEB-120",
"GDX-SOFUZ4",]}
i tried with e value onchange code but then I always get error that data.map is not a function.

Related

Array has duplicated records when using checkboxes to populate an array using React

I have trouble with simple task of adding elements selected in checkboxes to an array in component state. It seems like the push method for state.toppings (Editor.js) is invoked twice for each checkbox click, even though console.log shows that updateFormValueCheck method is invoked once per click. Can anyone help?
This is App.js
import React, { Component } from "react";
import { Editor } from "./Editor";
import { Display } from "./Display";
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
formData: {}
}
}
submitData = (newData) => {
console.log("newData", newData)
this.setState({ formData: newData });
}
render() {
return <div className="container-fluid">
<div className="row p-2">
<div className="col-6">
<Editor submit={this.submitData} />
</div>
<div className="col-6">
<Display data={this.state.formData} />
</div>
</div>
</div>
}
}
This is Editor.js
import React, { Component } from "react";
export class Editor extends Component {
constructor(props) {
super(props);
this.state = {
toppings: ["Strawberries"]
}
this.toppings = ["Sprinkles", "Fudge Sauce",
"Strawberries", "Maple Syrup"]
}
updateFormValueCheck = (event) => {
event.persist();
this.setState(state => {
if (event.target.checked) {
state.toppings.push(event.target.name);
} else {
let index = state.toppings.indexOf(event.target.name);
state.toppings.splice(index, 1);
}
}, () => this.props.submit(this.state));
}
render() {
return <div className="h5 bg-info text-white p-2">
<div className="form-group">
<label>Ice Cream Toppings</label>
{this.toppings.map(top =>
<div className="form-check" key={top}>
<input className="form-check-input"
type="checkbox" name={top}
value={this.state[top]}
checked={this.state.toppings.indexOf(top) > -1}
onChange={this.updateFormValueCheck} />
<label className="form-check-label">{top}</label>
</div>
)}
</div>
</div>
}
}
This is Display.js
import React, { Component } from "react";
export class Display extends Component {
formatValue = (data) => Array.isArray(data)
? data.join(", ") : data.toString();
render() {
let keys = Object.keys(this.props.data);
if (keys.length === 0) {
return <div className="h5 bg-secondary p-2 text-white">
No Data
</div>
} else {
return <div className="container-fluid bg-secondary p-2">
{keys.map(key =>
<div key={key} className="row h5 text-white">
<div className="col">{key}:</div>
<div className="col">
{this.formatValue(this.props.data[key])}
</div>
</div>
)}
</div>
}
}
}
The output is:
You cannot directly mutate this.state, it can only be done using this.setState. For more info. refer this: Why can't I directly modify a component's state, really?
Therefore, you need to update your Editor component as follows.
componentDidMount is used to display the initial state during the initial rendering. Then componentDidUpdate is used to render the state changes through display component whenever it's updated.
import React, { Component } from "react";
export class Editor extends Component {
constructor(props) {
super(props);
this.state = {
toppings: ["Strawberries"],
};
this.toppings = ["Sprinkles", "Fudge Sauce", "Strawberries", "Maple Syrup"];
}
updateFormValueCheck = (event) => {
event.persist();
let data;
if (event.target.checked) {
data = [...this.state.toppings, event.target.name];
} else {
const index = this.state.toppings.indexOf(event.target.name);
const temp = [...this.state.toppings];
temp.splice(index, 1);
data = temp;
}
this.setState({
toppings: data,
});
};
componentDidMount() {
this.props.submit(this.state.toppings);
}
componentDidUpdate(prevPros, prevState) {
if (prevState.toppings !== this.state.toppings) {
this.props.submit(this.state.toppings);
}
}
render() {
console.log(this.state);
return (
<div className="h5 bg-info text-white p-2">
<div className="form-group">
<label>Ice Cream Toppings</label>
{this.toppings.map((top) => (
<div className="form-check" key={top}>
<input
className="form-check-input"
type="checkbox"
name={top}
value={this.state[top]}
checked={this.state.toppings.indexOf(top) > -1}
onChange={this.updateFormValueCheck}
/>
<label className="form-check-label">{top}</label>
</div>
))}
</div>
</div>
);
}
}
Hope this would be helpful to solve your issue.

Im not understanding why I'm recieving the error "Cannot read property 'map' of undefined" in React

Im trying to load the information from a database to my React App. Everything is working as expected except for the map function I'm running. Im trying to list all the genres of the given movie in the div.
import React, { Component } from 'react';
import axios from 'axios';
import ReactPlayer from 'react-player';
import play from '../../img/play-icon.svg';
import './hero-display.scss';
class HeroDisplay extends Component {
constructor() {
super();
this.state = {
movie: {},
trailer: false
}
}
componentDidMount() {
axios.get('https://petflix.herokuapp.com/movie')
.then((response) => {
this.setState({
movie: response.data
})
})
.catch((error) => {
console.error(error);
});
}
openTrailer = () => {
this.setState({
trailer: true
});
}
closeTrailer = () => {
this.setState({
trailer: false
});
}
render() {
const { movie, trailer } = this.state;
return (
<>
<div className="hero-display__container" style={{backgroundImage: `url(${movie.backdropURL})`}}>
<div className="hero-display__movie-information">
<img className="hero-display__movie-logo" src={movie.logoURL} alt=""/>
<h1 className="hero-display__heading">Watch Now</h1>
<p className="hero-display__movie-description">{movie.description}</p>
<div className="hero-display__control-buttons">
<button onClick={this.openTrailer} className="hero-display__button play">
<img src={play} alt=""/>
Play Trailer
</button>
</div>
</div>
<div className="hero-display__rating">
<p>{movie.rating}</p>
</div>
</div>
<div className={trailer ? "movie__trailer showing" : "movie__trailer hidden"}>
<div className="movie-trailer__container">
<button className="movie-trailer__close-button" onClick={this.closeTrailer}></button>
<ReactPlayer className="video-player" light={movie.backdropURL} volume={0} loop={true} playing={true} image={movie.backdropURL} muted={false} url={movie.trailerURL}/>
<div className="movie__information">
<div className="movie-trailer__title-add">
<h1 className="movie-trailer__title">{movie.title}</h1>
<button className="movie-trailer__button"></button>
</div>
<p className="movie-trailer__rating">{movie.rating}</p>
<p className="movie-trailer__director">Directed By: {movie.director}</p>
<p className="movie-trailer__description">{movie.description}</p>
{movie.genres.map((genre) => {
return (
<p className="movie-trailer__genres">{genre}</p>
)
})}
</div>
</div>
</div>
</>
)
}
}
export default HeroDisplay;
The map function works in a different functional component when the state is passed as a prop, but not in the class component itself. Id appreciate the help.
An example of a movie object that is stored in state.
{
"title": "101 Dalmatians",
"description": "A brave young man is thrust into adulthood as he and his courageous team of sled dogs embark on a grueling and treacherous cross-country marathon.",
"director": "Stephen Herek",
"genres": [
"Adventure",
"Family",
"Comedy"
],
"rating": "G",
"backdropURL": "https://www.themoviedb.org/t/p/original/mz75dVXfen4J1Z0R8DbTenXNywz.jpg",
"posterURL": "https://www.themoviedb.org/t/p/original/8o2ADoAyG796UwTjwBFjPyBz0yG.jpg",
"trailerURL": "https://www.themoviedb.org/video/play?key=K2CTJS12RdI",
"logoURL": "https://www.themoviedb.org/t/p/original/noruOCRUoWndPPDPJYdR7kVsiq5.png"
}
It is happening due to the generes property of movie state is not available before the api call.
So instead of direct access of property.
{movie.genres.map((genre) => {
return (
<p className="movie-trailer__genres">{genre}</p>
)
})}
use optional chaining with ?.
{movie?.genres?.map((genre) => {
return (
<p className="movie-trailer__genres">{genre}</p>
)
})}
This part:
{movie.genres.map((genre) => {
return (
<p className="movie-trailer__genres">{genre}</p>
)
})}
Should be
{movie.genres && movie.genres.map((genre) => {
return (
<p className="movie-trailer__genres">{genre}</p>
)
})}
Alternatively, you could do movie?.genres?.map((genre) => {...
Otherwise movie.genres is undefined on first render.

How to print list output dynamically in React JS as buttons

Below is the code snippet of my ReactJS component, I'm trying to put the output with a button beside it in a list format. The output which is received in the "axios" get function is from an api and it is in this format: [{'name': 'i-cc608f4d'}, {'name': 'i-fd608f7c'}, {'name': 'i-fe608f7f'}]
I want to list these IDs with a button besides it.
import React, { Component } from "react";
import axios from "axios";
const pStyle = {
backgroundColor: "#79D3EF",
color: "white"
};
export default class CityContent extends Component {
constructor(props) {
super(props);
this.state = {
citydetail: []
};
}
componentDidMount() {
axios.get("http://127.0.0.1:8000/Delhi").then(res => {
const citydetail = res.data;
this.setState({ citydetail });
});
}
render() {
return (
<div className="content-wrapper">
<section className="content-header">
<div className="row">
<div className="col-md-4">
<div className="box">
<div className="box-body">
<div className="row">
<div className="col-md-8">
<ul>{this.state.citydetail.state}</ul>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
}
What should I write to replace {this.state.citydetail.state}.
Because currently, it's printing the API output itself.
<div className="col-md-8">
<ul>
{
this.state.citydetail.map((city) => (
<li>{city.name}<button>Click</button></li>
)}
</ul>
</div>
This code will print your output and map will map through that data of citydetail and button beside it.
It should be something like this
<ul>
{
this.state.citydetail.map((city, index) => (
<li key={index}>{city.name}<button>{city.name}</button></li>
)}
</ul>
Update
Set your state like this in componentDidMount()
this.setState({ citydetail : citydetail });
Update 2 (after OP comment)
I cannot change the format of this output...
try this
axios.get("http://127.0.0.1:8000/Delhi").then(res => {
const citydetail = res.data;
let arrData = JSON.parse(citydetail.replace(/'/g, '"'));
this.setState({ citydetail: arrData });
});

React - Map content inside a div

Good Morning! Why does my map content stay outside the "blog--div" div?
It's getting loose on Body and I do not know why. Help-me, please!
I try to put a border around the contents of the "blog--div" but the content becomes loose, making it impossible to apply styles.
imports[...]
class Blog extends Component {
constructor(props) {
super(props)
this.state = {
post: [],
}
}
componentDidMount() {
this.setState({ isLoading: true })
fetch(`${API}`)
.then(res => res.json())
.then(res => {
this.setState({
post: [res],
isLoading: false,
})
})
}
render() {
const { isLoading } = this.state
if (isLoading) {
return <Loading />
}
return (
<div className="blog">
<p className="blog__title">Blog</p>
{this.renderBlog()}
</div>
)
}
renderBlog() {
const page = this.state.post.map((post, key) => {
return (
<div className="blog--div" key={key}>
<div className="blog__post">
<div className="blog__post--title">
<p><a target="_blank" rel="noopener noreferrer" href={post[0].link}>{post[0].title.rendered.replace('Visit.Rio', 'Projeto 1')}</a></p>
</div>
<div className="blog__post--description">
<p>{post[0].excerpt.rendered.replace('Visit.Rio', 'Projeto 1')}</p>
</div>
</div>
</div>
)
})
return page
}
}
export default Blog

Updating State Breaks Child Prop Component

I am still trying to get a handle on parent-child data sharing and have an issue where my stateful component has an array of objects that display correctly within my child prop components via componentWillReceiveProps(), but when I trigger my updateCommentsFunc() function, which is triggered by a child component form, the POST is called and value is appended to the array, but I get an undefined error from my child component that demonstrates that the data isn't flowing post state update.
Am I using the wrong method? Should I add something to my updateCommentsFunc()?
Here is the console error:
Uncaught TypeError: Cannot read property 'picture' of undefined
at Comment (comment.js?2fa6:15)
at mountIndeterminateComponent (react-dom.development.js?cada:10400)
at beginWork (react-dom.development.js?cada:10601)
at performUnitOfWork (react-dom.development.js?cada:12573)
at workLoop (react-dom.development.js?cada:12682)
at HTMLUnknownElement.callCallback (react-dom.development.js?cada:1299)
at Object.invokeGuardedCallbackDev (react-dom.development.js?cada:1338)
at invokeGuardedCallback (react-dom.development.js?cada:1195)
at performWork (react-dom.development.js?cada:12800)
at scheduleUpdateImpl (react-dom.development.js?cada:13185)
Triggered at line:
<img src={props.user.picture} className="comment__record-profile"/>
This is the parent component which is fed an object that has its nested array mapped and stored in an array in the state:
//Loop through JSON and create Comment and Comment Container Component
class CommentFeed extends React.Component {
constructor(props){
super(props);
this.state = {
comments: []
};
this.updateCommentsFunc = this.updateCommentsFunc.bind(this);
}
//Load Array to component
componentWillReceiveProps(nextProps){
let commentArr = [];
nextProps.comments.map((comment) => {
comment.comment_comments.map((comment) => {
commentArr.push(comment);
})
})
this.setState({comments: commentArr});
}
//Append new POST value to commentArr
updateCommentsFunc(newComments){
var updatedCommentArr = this.state.comments.slice();
updatedCommentArr.push(newComments)
this.setState({comments: updatedCommentArr});
}
render(){
return (
<div>
{
this.props.comments.map((comment, index) => {
return (
<div className="row">
<div className="col-md-6 col-md-offset-3 comment-card">
<CommentCard {...comment} key={comment.commentIdHash} user={this.props.user} />
<Comments comments={this.state.comments} key={index} commentId={comment.commentIdHash} csrf={this.props.csrf} updateComments={this.updateCommentsFunc}/>
</div>
</div>
);
})
}
</div>
);
}
}
Here is the child component split into a form and displayed comments:
//Blog Comment - Container
export default class Comments extends React.Component {
render() {
return (
<div className="blog-comment-container">
<CommentForm updateComments={this.props.updateComments} blogId={this.props.blogId} csrf={this.props.csrf}/>
{ this.props.comments.map((comment, i) =>
<AttachedComment commentObj={comment} blogComponentId={this.props.blogId}/>
)}
</div>
);
}
}
Here is the form calling this.props.updateComments() with the returned JSON data from the POST:
class CommentForm extends React.Component {
constructor(props){
super(props);
this.state = {
value: ''
};
this.postComment = this.postComment.bind(this);
this.onChange = this.onChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
postComment(comment, blogId, csrfToken) {
var body = { comment: comment };
var route = 'http://localhost:3000/app/blog/' + blogId + '/comment';
fetch(route,
{
method: 'POST',
body: JSON.stringify(body),
headers: {
'X-CSRF-Token': csrfToken,
'Accept': 'application/json',
'Content-Type': 'application/json'
}
})
.then(res => {
return res.json();
})
.then(data => {
this.props.updateComments(data)
})
.catch(err => {
console.log(err);
});
}
onChange(e){
this.setState({
value: e.target.value
});
}
handleSubmit(e){
e.preventDefault();
this.postComment(this.state.value, this.props.blogId, this.props.csrf);
}
render(){
return (
<div className="blog-comment__form">
<div className="row">
<div className="col-md-12">
<label>Comment:</label>
</div>
</div>
<div className="row">
<form action={"/app/blog/" + this.props.blogId + "/comment"} method="post" onSubmit={this.handleSubmit}>
<input type="hidden" name="_csrf" value={this.props.csrf}/>
<div className="col-md-9">
<textarea name="comment" className="blog-comment__form-text-area" onChange={e => this.setState({ value: e.target.value })} value={this.state.value}></textarea>
</div>
<div className="col-md-3">
<button type="submit" className="blog-comment__form-button" disabled={!this.state.value}>Comment</button>
</div>
</form>
</div>
</div>
)
}
}
Here is the conditional that checks to see if the nested array Id matches the id from the fed object at the parent:
const AttachedComment = props => {
if(props.commentObj.blogIdHash == props.blogComponentId){
return (
<Comment {...props.commentObj} key={props.commentObj.blogCommentId}/>
)
} else {
return null;
}
}
Finally, if that returns TRUE then the component where the error appeared is rendered:
const Comment = props => {
return (
<div className="comment-comment__record">
<div className="row">
<div className="col-md-12">
<div className="comment-comment__meta">
<div className="row">
<div className="col-md-6">
<img src={props.user.picture} className="comment-comment__record-profile"/>
</div>
<div className="col-md-6">
</div>
</div>
</div>
<h5>{props.user_id}</h5>
<h4>{props.comment}</h4>
<h3>{props.synotate_user.fullNameSlug}</h3>
</div>
</div>
</div>
)
}

Resources