I have a component Active.js, that lists items thought axios get, and then there is a link on name (sub-component ActiveDetails.js) that I wish returns that specific object user clicks on in order to get more details. But it returns an empty object. ID is undefined. console
How link id of object to specific url?
import axios from 'axios';
import moment from 'moment';
import { Link } from 'react-router-dom';
export default class Active extends React.Component {
constructor(props) {
super(props)
this.state = {
activeVisitors: [],
};
}
componentDidMount() {
axios.get('http://localhost:8085/api/visitors/')
.then(res => {
this.setState({ activeVisitors: res.data._embedded.visitorList, });
})
.catch(error => {
console.log(error)
});
}
render() {
return (
<>
<h1>Active visitors</h1>
<div >
<ol>
{this.state.activeVisitors.map(activeVisitor =>
<li key={activeVisitor.id}>
<div>
<div>
<Link to={`/active/${activeVisitor.id}`}>Name: {activeVisitor.name}</Link>
</div> <br/>
<button onClick={this.handleRemoveClick}>Remove</button>
Time: {moment(activeVisitor.dateTime).format('MMMM Do YYYY, h:mm:ss a')}<br />
</div></li>)}
</ol>
</div>
</>
);
}
}
import React from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
export default class VisitorDetails extends React.Component {
constructor(props) {
super(props)
this.state = {
visitors: {},
};
}
componentDidMount() {
axios.get(`http://localhost:8085/api/visitors/${this.state.id}`)
.then(res => {
this.setState({ visitors: res.data._embedded.visitorList });
})
.catch(error => {
console.log(error)
});
}
render() {
return (
<>
<div className='item'>
{this.state.visitors.id}
Name: {this.state.visitors.name}
Badge Nr: {this.state.visitors.accessCardID}
</div>
</>
)
}
}
In your VisitorDetails.js extract the id from props as shown below. When you pass an id using react-router-dom that id will be added inside params of the match property from where you can access the id value.
In your case as the path associated with the component is '/active/:id', you can access the value using id prop as shown below
.........
.........
.........
componentDidMount() {
const { id } = this.props.match.params
axios.get(`http://localhost:8085/api/visitors/${id}`)
.then(res => {
this.setState({ visitors: res.data._embedded.visitorList });
})
.catch(error => {
console.log(error)
});
}
.........
.........
.........
Related
I want to redirect to index.html on clicking the div in react class component
i already having one on click function for passing value and also i tried all the ways
history.push
windows.location
withRouter but nothing works
and because of class component history.push gives a error as it cannot be used in class component
This is my js code
import React, { Component } from 'react';
import axios from 'axios';
class Tweet extends Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
this.handleClickHai = this.handleClickHai.bind(this);
this.handleClickHello = this.handleClickHello.bind(this);
}
handleClickHai(){
this.setState(state => ({
value: 'Hai'
}));
axios.get('/setvalue?value=Hi')
.then( function (response){
console.log(response)
})
.catch(function (error) {
console.log(error)
});
}
handleClickHello(){
this.setState(state => ({
value: 'Hello'
}));
axios.get('/setvalue?value=Hello')
.then( function (response){
console.log(response)
})
.catch(function (error) {
console.log(error)
});
}
render() {
return (
<div className="greet" >
<div className="hello" onClick={this.handleClickHello} >
<h4>Hello</h4>
</div>
<div className="hi" onClick={this.handleClickHai}>
<h4>Hi</h4>
</div>
</div>
);
}
}
export default Tweet;
when i click the hello div it will pass the value to variable and also i want it to redirect to html page
anyone help me with the code
Combine #1 and #3, wrap the component in withRouter and then use this.props.history.push()
import {withRouter} from "react-router-dom";
import React, { Component } from 'react';
import axios from 'axios';
class Tweet extends Component {
constructor(props) {
super(props);
this.state = {
value: null,
};
this.handleClickHai = this.handleClickHai.bind(this);
this.handleClickHello = this.handleClickHello.bind(this);
}
handleClickHai(){
this.setState(state => ({
value: 'Hai'
}));
axios.get('/setvalue?value=Hi')
.then( function (response){
console.log(response)
})
.catch(function (error) {
console.log(error)
});
}
// Redirects To home
redirectToHome(){
this.props.history.push('/');}
}
handleClickHello(){
this.setState(state => ({
value: 'Hello'
}));
axios.get('/setvalue?value=Hello')
.then( function (response){
console.log(response)
})
.catch(function (error) {
console.log(error)
});
}
render() {
return (
<div className="greet" >
<div className="hello" onClick={this.handleClickHello} >
<h4>Hello</h4>
</div>
<div className="hi" onClick={this.handleClickHai}>
<h4>Hi</h4>
</div>
</div>
);
}
}
export default withRouter(Tweet);
this is a general example to redirect user.
import { useHistory } from 'react-router-dom'
....
....
const history = useHistory();
....
....
history.push('/') //here you can redirect to where you want.
greetings,
Yo guys, getting error 'contacts.map is not a function' not sure why is that ? just starting in react maybe missing something obvious. I'm getting the data when I console log all good.
code below:
import React, { Component } from 'react'
import axios from 'axios';
class Contacts extends Component {
constructor(){
super();
this.state = {
contacts: [],
}
}
componentDidMount(){
axios.get('url')
.then(response => {
this.setState({ contacts: response.data });
})
.catch(function (error) {
console.log(error);
})
}
render() {
const { contacts } = this.state
return(
<div>
{contacts.map(contact => (
<h1>contact.hello</h1>
))}
</div>
)
}
}
export default Contacts;
Apparently its an object not an array...
How can i render this object then?
It has one property for now but will have more later on: tried JSON.stringify(obj)
{hello: "test"}
The problem is that you set contacts to response.data, which evidently it's not an array.
componentDidMount fires after the component is mounted and tries to get the string 'url'. When state is updated, the component is redrawn and it gives the error.
Since the contacts is an object I would recommend you to do Object.keys and then .map on it so that you can get object keys and it’s values.
One more thing never forget to add unique key to the parent jsx element when you iterate array of data or an object like below.
<div>
{Object.keys(contacts).map((name, index) => (
<h1 key={'Key'+index}>{contacts[name]}</h1>
))}
</div>
From react docs:
Note:
These methods are considered legacy and you should avoid them in new code:
UNSAFE_componentWillMount()
When you want to wrap an object you can simply wrap it in brackets
class Contacts extends Component {
constructor() {
super();
this.state = {
contacts: [],
}
}
componentDidMount() {
axios.get('url')
.then(({ data }) => {
this.setState({ contacts: [data] });
})
.catch((error) => {
console.log(error);
});
}
render() {
const { contacts } = this.state;
return (
<div>
{contacts.map(contact => (
<h1 key={/* unique key */}>contact.hello</h1>
))}
</div>
);
}
}
Use async await to get the response before the component is mounted
import React, { Component } from 'react'
import axios from 'axios';
class Contacts extends Component {
constructor(){
super();
this.state = {
contacts: [],
}
}
async componentWillMount(){
const response = await axios.get('url')
this.setState({ contacts: response.data })
}
render() {
const { contacts } = this.state
return(
<div>
{contacts.map(contact => (
<h1>contact.hello</h1>
))}
</div>
)
}
}
export default Contacts;
I have a list of posts and for every post, there's is a button that will display a modal window with a confirmation if the user really wants to delete the respective post.
When the user confirms, data are send to backend, there's delete the respective post and back to ReactJS is returned a set of all posts. But when try to update the list of posts on the front-end, I get this error:
Posts.jsx:61 Uncaught (in promise) TypeError: _this2.props.posts is not a function
This error is raised on this line:
this.props.posts(res.data);
Home.jsx
import React from "react";
import Posts from './Posts';
import NewPost from './NewPost';
import axios from 'axios';
import Moment from 'react-moment';
import LoadModal from './LoadModal';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: [],
loading: true
};
}
componentDidMount() {
axios.get('/posts')
.then(response => {
console.log('---');
console.log(response.data);
console.log('---');
this.setState({ posts: response.data, loading: false });
});
}
render() {
return (
<div>
<Posts posts={this.state.posts} loading={this.state.loading} />
</div>
)
}
}
export default Home
Posts.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import {Collapse} from 'react-collapse';
import classNames from "classnames";
import Dialog from 'react-bootstrap-dialog';
class Posts extends React.Component {
constructor(props) {
super(props);
this.state = {
activeIndex: null,
removePostBtn: 'Remove'
}
}
onClick(post_id) {
this.dialog.show({
title: 'Remove Post - #'+post_id,
body: 'Do you really want to remove this post?',
actions: [
Dialog.CancelAction(),
Dialog.DefaultAction(
this.state.removePostBtn,
() => {
this.setState({ removePostBtn: 'Removing...' }, () => {
axios.get('/remove_post/'+post_id, { post_id: post_id })
.then(res => {
this.props.posts(res.data); // here's the error
})
})
},
'btn-danger'
)
],
})
}
render () {
let content;
const { activeIndex } = this.state;
const Button = require('react-bootstrap').Button;
if (this.props.loading) {
content = 'Loading...';
} else {
content = this.props.posts.map((post, index) => {
return(
<li key={index}>
<div>
<span>{post.id}</span>
<span>{post.message}</span>
<Button onClick={() => this.onClick(post.id)}>Show alert</Button>
<Dialog ref={(el) => { this.dialog = el }} />
</div>
</li>
)
});
}
return (
<div>
<h1>Posts!</h1>
<div className="row">
<div className="col-md-6">
<ul>
{content}
</ul>
</div>
</div>
</div>
);
}
}
export default Posts
How do I properly update the props with posts?
You can't directly update any props. You need to create an update handler in the parent component that will update this.state.posts:
import React from "react";
import Posts from './Posts';
import NewPost from './NewPost';
import axios from 'axios';
import Moment from 'react-moment';
import LoadModal from './LoadModal';
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
posts: [],
loading: true
};
}
componentDidMount() {
this.getPosts();
}
getPosts = () => {
axios.get('/posts')
.then(response => {
console.log('---');
console.log(response.data);
console.log('---');
this.setState({ posts: response.data, loading: false });
});
}
updatePosts = posts => {
this.setState({ posts });
}
render() {
return (
<div>
<Posts posts={this.state.posts} loading={this.state.loading} getPosts={this.getPosts} updatePosts={this.updatePosts} />
</div>
)
}
}
export default Home
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import {Collapse} from 'react-collapse';
import classNames from "classnames";
import Dialog from 'react-bootstrap-dialog';
class Posts extends React.Component {
constructor(props) {
super(props);
this.state = {
activeIndex: null,
removePostBtn: 'Remove'
}
}
onClick(post_id) {
this.dialog.show({
title: 'Remove Post - #'+post_id,
body: 'Do you really want to remove this post?',
actions: [
Dialog.CancelAction(),
Dialog.DefaultAction(
this.state.removePostBtn,
() => {
this.setState({ removePostBtn: 'Removing...' }, () => {
axios.get('/remove_post/'+post_id, { post_id: post_id })
.then(res => {
//this.props.posts(res.data); // here's the error
// Call parent function to re-retch posts
this.props.getPosts();
// Or direclty pass data to update the parent state
this.props.updatePosts(res.data);
})
})
},
'btn-danger'
)
],
})
}
render () {
let content;
const { activeIndex } = this.state;
const Button = require('react-bootstrap').Button;
if (this.props.loading) {
content = 'Loading...';
} else {
content = this.props.posts.map((post, index) => {
return(
<li key={index}>
<div>
<span>{post.id}</span>
<span>{post.message}</span>
<Button onClick={() => this.onClick(post.id)}>Show alert</Button>
<Dialog ref={(el) => { this.dialog = el }} />
</div>
</li>
)
});
}
return (
<div>
<h1>Posts!</h1>
<div className="row">
<div className="col-md-6">
<ul>
{content}
</ul>
</div>
</div>
</div>
);
}
}
export default Posts
Task is to fetch data from api when toggle between tags
When click on the link it calls the api service but state of feeds is not updated but it throws below warning
jQuery.Deferred exception: Cannot read property 'setState' of undefined TypeError: Cannot read property 'setState' of undefined
My github repo
https://github.com/dolphine4u/demo-app
APP component
import React from 'react';
import {FetchData} from "../service/flickerApi.service";
import Header from "./header/header.component";
import Navigation from "./navigation/navigation.component";
import ProductList from "./products/products.component";
import Footer from "./footer/footer.component";
class App extends React.Component {
constructor() {
super()
this.state = {
feeds: [],
favorites:[]
};
this.addToFavorites = this.addToFavorites.bind(this);
}
handleChange( value ) {
this.setState( { feeds: value })
}
addToFavorites(id) {
const {feeds ,favorites} = this.state;
const findId = feeds.filter(item => {
return item.id === id;
})
favorites.push(findId)
console.log(favorites)
// localStorage.setItem('favorite', JSON.stringify(this.state.favorites));
this.setState({
feeds: favorites
});
}
/* componentWillMount(){
let LoadFeeds = localStorage.getItem('FlickerFeeds');
LoadFeeds && this.setState({
feeds: JSON.parse(LoadFeeds)
})
}*/
componentDidMount() {
FetchData.call(this);
}
/* componentWillUpdate(nextprops, nextState){
localStorage.setItem('FlickerFeeds', JSON.stringify(nextState.feeds))
}
*/
render() {
const {feeds} = this.state;
const productList = feeds.map((item,index) => {
return <ProductList
key={index}
title={item.title}
image={item.src}
id={item.id}
author={item.author}
date={item.created}
update={this.addToFavorites}
/>
})
return ([
<Header key="header"/>,
<Navigation key="navigation" />,
<section key="productList">
<div className="container">
<div className="row row-eq-height">
{productList}
</div>
</div>
</section>,
<Footer key="footer"/>
]);
}
}
export default App;
Navigation component
import React from 'react';
import Link from "./link.component";
import './navigation.css';
class Navigation extends React.Component {
constructor(props) {
super(props)
this.state = {
tags: [
{tag:"kittens"},
{tag:"dogs"},
{tag:"lion"},
{tag:"tiger"},
{tag:"leapord"}]
};
}
render() {
const {tags} = this.state;
const tagList = tags.map(item => {
return <Link
key={item.tag}
tag={item.tag}
/>
})
return (
<nav className="nav">
<div className="container">
<ul className="nav-bar">
{tagList}
</ul>
</div>
</nav>
);
}
}
export default Navigation;
Link Component
import React from 'react';
import {FetchData} from "../../service/flickerApi.service";
class Link extends React.Component {
constructor(props) {
super(props)
this.onClick = this.onClick.bind(this);
}
onClick(e) {
FetchData(this.props.tag);
}
render() {
return (
<li><a href="#" onClick={this.onClick}>{this.props.tag}</a></li>
);
}
}
export default Link;
product component
import React from 'react';
import './product.css';
class ProductList extends React.Component {
constructor(props) {
super(props);
this.onClick = this.onClick.bind(this);
}
onClick(e) {
this.props.update(this.props.id);
}
render() {
return (
<div className="product-column">
<div className="product-item">
<div className="product-content">
<div className="product-author">
<strong>Author: </strong>{this.props.author}
</div>
{/*<div className="product-image" style={{backgroundImage: "url(" + this.props.image + ")"}}/>*/}
</div>
<div className="product-content">
<div className="product-date">
Created Date: {this.props.date}
</div>
<h3 className="product-title">{this.props.title}</h3>
<button className="product-btn" onClick={this.onClick}>
Add to Favourites
</button>
</div>
</div>
{/*<div className="product-description" dangerouslySetInnerHTML={{__html: this.props.description}}>
</div>*/}
</div>
);
}
}
export default ProductList;
Api service
import $ from "jquery";
import {getLastPartOfUrl, formatDate, removeUrl, getString} from "../helpers/helper";
export function FetchData(tag) {
const URL = "https://api.flickr.com/services/feeds/photos_public.gne?format=json&jsoncallback=?"
const SUFFIX_SMALL_240 = "_m";
const SUFFIX_SMALL_320 = "_n";
$.getJSON({
url : URL,
data: {
tags: tag
}
})
.then(response => {
let list= response.items.map(item => ({
title: removeUrl(item.title),
id: getLastPartOfUrl(item.link),
description: item.description,
link: item.link,
src: item.media.m.replace(SUFFIX_SMALL_240, SUFFIX_SMALL_320),
author: getString(item.author),
created: formatDate(item.published),
tags: item.tags,
fav: false
}));
this.setState({
feeds: list
})
}).catch(function(error){
console.log(error);
});
}
You're trying to call this.addToFavorites from a click handler that is not even bound to this. I think two changes are needed for this to work:
In App component, change the addFavorites function to an arrow function so it gets the context this:
addToFavorites = id => {
...
Same in ProductList component for the click handler:
onClick = () => {
this.props.update(this.props.id);
}
single.js :
import React, { Component } from 'react';
import Details from '../components/details'
import { ProgressBar } from 'react-materialize';
import { Route, Link } from 'react-router-dom';
const Test = () => (
<div> RENDER PAGE 1</div>
)
class SinglePage extends Component {
constructor(props) {
super(props);
this.state = {
data: null,
}
}
componentDidMount() {
fetch('http://localhost:1337/1')
.then((res) => res.json())
.then((json) => {
this.setState({
data: json,
});
});
}
render() {
const { data } = this.state;
return (
<div>
<h2> SinglePage </h2>
{!data ? (
<ProgressBar />
) : (
<div>
<Details data={data} />
</div>
)}
</div>
);
}
}
export default SinglePage;
details.js :
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class Details extends Component {
static propTypes = {
item: PropTypes.shape({
date: PropTypes.string.isRequired,
}).isRequired,
}
render() {
const { item } = this.props;
return (
<div>
<p> {item.date} </p>
</div>
)
}
}
export default Details;
In console, I am getting an error : Warning: Failed prop type: The prop item is marked as required in Details, but its value is undefined.
From this I though my json was not catched but I have an other component which fetch on http://localhost:1337/ , get datas and display them correctly, and going to http://localhost:1337/1 send me a json response so I'm quite confused here.
Additional screenshot :
SinglePage is passing date props with name data as oppose to item that is defined in Details
<Details item={date} />
Also adding init value for date
constructor(props) {
super(props);
this.state = {
date: { date: null },
}
}