react : why is axios api call not using proxy in package.json? - reactjs

I have a react app that i've made and it is working great in storybook with a mock for data retrieving.
When I switch to yarn start to check the app without mock, the page is loading some components but not the main component (PostPageCardContainer) which is only displaying "loading" (see the code below).
The component which load properly make api calls like this in ComponentDidMount :
axios.get("/api/blog/categories/").then((res) => {
const categories = res.data.results;
this.setState({
categories,
loading: false });
and
axios.get("/api/blog/tags/").then((res) => {
const tags = res.data.results;
this.setState({
tags,
loading: false });
}); }
The components that dont load make an api call like this in COmponentDidMount:
PostPageCard.js:
const pk = this.props.match.params.id;
axios.get(`/api/cms/pages/${pk}/`).then((res) => {
const post = res.data;
this.setState({
post,
loading: false });
}) }
PostDetail.js
axios.get(`/api/cms/pages/${this.props.postPk}/`).then((res) => {
this.setState({
data: res.data,
loading: false
}); });
In the browser console, when i try to load the page i get :
printWarnings # webpackHotDevClient.js:138
:3000/api/cms/pages/6/:1
Failed to load resource: the server responded with a status of 404 (Not Found)
And when i hover the mouse on the link i get http://localhost:3000/api/cms/pages/6.
In fact the react page is being served on localhost:3000 but I have put "proxy": "http://172.20.128.2:8000" in packages.json so my api call go on this adress.
How come some api calls go on the good adress and others dont?
The issue is similar to this : How to set proxy when using axios to send requests? and this Axios not using proxy setting with https and this axios request ignores my proxy and even when hardcoded I can't fetch any data but there is not really a solution except using fetch or restarting the machine
I ve tried to hardcode the proxy in the api call like axios.get(http://172.20.128.2:8000/api/cms/pages/${this.props.postPk}` and removed the proxy line from package.json but then nothing is loading properly...
Here is some sample of the code:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./components/App";
import 'bootstrap/dist/css/bootstrap.css';
import { MemoryRouter } from "react-router-dom";
ReactDOM.render(
<React.StrictMode>
<MemoryRouter initialEntries={["/"]}>
<App/>
</MemoryRouter>
</React.StrictMode>,
document.getElementById("root")
);
App.js
import React from "react";
import { Route, Switch } from "react-router";
import { Container, Row } from "react-bootstrap";
import { BlogPage } from "./BlogPage";
import { PostPage } from "./PostPage";
function App() { return (
<Switch>
<Route path="/post/:id([\d]+)" component={PostPage}/>
<Route path="/tag/:tag/:page([\d]+)?" component={BlogPage}/>
<Route path="/:page([\d]+)?" component={BlogPage}/>
<Route
path="*"
component={() => (
<Container> <Row>
<h1>404</h1> </Row>
</Container> )}
/> </Switch>
); }
export default App;
BlogPage.js
import React from "react";
import { Container, Row } from "react-bootstrap";
import { TopNav } from "./TopNav";
import { Footer } from "./Footer";
import { PostPageCardContainer } from "./PostPageCardContainer";
import { SideBar } from "./SideBar";
class BlogPage extends React.Component { render() {
return (
<div>
<TopNav />
<Container>
<Row>
<PostPageCardContainer {...this.props} />
<SideBar />
</Row>
</Container>
<Footer />
</div> );
} }
export { BlogPage };
Postpagecardcontainer.js
import React from "react";
import axios from "axios";
import { Col } from "react-bootstrap";
import { Link } from "react-router-dom";
import { generatePath } from "react-router";
import _ from 'lodash';
import { PostPageCard } from "./PostPageCard";
class PostPageCardContainer extends React.Component {
constructor(props) {
super(props); this.state = {
posts: [],
pageCount: 0,
pageStep: 2,
};
this.getPosts = this.getPosts.bind(this);
}
componentDidMount() {
this.getPosts();
}
componentDidUpdate(prevProps) {
if (prevProps.location !== this.props.location) {
this.getPosts(); }
}
getCurPage() {
// return the page number from the url
const page = this.props.match.params.page;
return page === undefined ? 1 : parseInt(page);
}
getPrePageUrl() {
const target = _.clone(this.props.match.params);
target.page = this.getCurPage() - 1;
return generatePath(this.props.match.path, target);
}
getNextPageUrl() {
const target = _.clone(this.props.match.params);
target.page = this.getCurPage() + 1;
return generatePath(this.props.match.path, target);
}
getPosts() {
let category = this.props.match.params.category === undefined ? "*" : this.props.match.params.category;
let tag = this.props.match.params.tag === undefined ? "*" : this.props.match.params.tag;
let offset = (this.getCurPage() - 1) * this.state.pageStep;
const url = `/api/blog/posts/?limit=${this.state.pageStep}&offset=${offset}&category=${category}&tag=${tag}`;
axios.get( url).then((res) => {
const posts = res.data.results;
this.setState({
posts,
pageCount: Math.ceil(parseInt(res.data.count) / this.state.pageStep),
});
});
}
render() {
return (
<Col md={8}> {this.state.posts.map((post) => (
<PostPageCard postPk={post.id} key={post.id} /> ))}
<nav aria-label="Page navigation example">
<ul className="pagination">
<li className={
this.getCurPage() <= 1 ? "page-item disabled" : "page-item" }>
<Link to={this.getPrePageUrl()}
className="page-link" >
Previous
</Link>
</li>
<li className={this.getCurPage() >= this.state.pageCount ? "page-item disabled" : "page-item" }>
<Link to={this.getNextPageUrl()}
className="page-link" >
Next
</Link>
</li>
</ul>
</nav>
</Col>
);
}
}
export { PostPageCardContainer };
PostPage.js
import React from "react";
import { Container, Row } from "react-bootstrap";
import { TopNav } from "./TopNav";
import { Footer } from "./Footer";
import { SideBar } from "./SideBar";
import { PostDetail } from "./PostDetail";
class PostPage extends React.Component { render() {
return ( <div>
<TopNav/> <Container>
<Row>
<PostDetail {...this.props} /> <SideBar/>
</Row> </Container> <Footer/>
</div> );
} }
export { PostPage };
PostDetail.js
import React from "react";
import axios from "axios";
import { StreamField } from "./StreamField/StreamField";
class PostDetail extends React.Component {
constructor(props) {
super(props); this.state = {
post: [],
loading: true, };
}
componentDidMount() {
const pk = this.props.match.params.id;
axios.get(`/api/cms/pages/${pk}/`).then((res) => {
const post = res.data;
this.setState({
post,
loading: false });
}) }
render() {
if (!this.state.loading) {
const post = this.state.post;
return (
<div className="col-md-8">
<img src={post.header_image_url.url} className="img-fluid rounded" alt=""/>
<hr />
<h1>{post.title}</h1>
<hr />
<StreamField value={post.body} />
</div> );
}
else {
return <div className="col-md-8">Loading...</div>;
}
}
}
export { PostDetail };
PostPageCard.js
import React from "react";
import { Link } from "react-router-dom";
import axios from "axios";
class PostPageCard extends React.Component {
constructor(props) {
super(props); this.state = {
data: null,
loading: true,
};
}
componentDidMount() {
axios.get(`/api/cms/pages/${this.props.postPk}/`).then((res) => {
this.setState({
data: res.data,
loading: false
}); });
}
renderPost(data) {
const dateStr = new Date(data.pub_date).toLocaleString();
return (
<div className="card mb-4">
<Link to={`/post/${data.id}`}> <img src={data.header_image_url.url} className="card-img-top" alt=""/> </Link>
<div className="card-body">
<h2 className="card-title">
<Link to={`/post/${data.id}`}>{data.title}</Link>
</h2>
<p className="card-text">{data.excerpt}</p>
<Link to={`/post/${data.id}`} className="btn btn-primary">Read More → </Link>
</div>
<div className="card-footer text-muted">Posted on {dateStr}
</div>
</div>
); }
render() {
if (this.state.loading) {
return 'Loading...'; }
else{
return this.renderPost(this.state.data); }
} }
export { PostPageCard };

Related

Can not pass props to component

I am creating an embedded react application into a wordpress site. I have fetched the data to show a list of posts however I can not pass the props to the Single post page. I can only think that it has something to do with the BrowserRouter and react-router-dom. I've searched Stack Overflow and can not find anything that is recent, the things I have tried have all failed. There maybe something very simple that I am missing.
Home.js
import React from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import "../sass/home.scss";
class Home extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
posts: [],
error: "",
};
}
componentDidMount() {
const wordPressSiteUrl = "http://localhost/wordpress";
this.setState({ loading: true }, () => {
axios
.get(`${wordPressSiteUrl}/wp-json/acf/v3/property`)
.then((res) => {
this.setState({ loading: false, posts: res.data });
console.log(res.data);
})
.catch((error) =>
this.setState({ loading: false, error: error.response.data })
);
});
}
render() {
const { posts } = this.state;
return (
<div>
{posts.length ? (
<div className="post-container">
{posts.map((post) => (
<div key={post.id} className="card">
<div className="card-header">
<Link to={`/property/${post.id}`}>
{post.acf.property_title}
</Link>
</div>
<div className="card-img-top">
<img src={post.acf.featured_image.url} alt="" />
{console.log(post.id)}
</div>
</div>
))}
</div>
) : (
""
)}
</div>
);
}
}
export default Home;
As it stands, I am getting undefined in the console log.
SinglePost.js;
import React from "react";
import axios from "axios";
class SinglePost extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
post: {},
error: "",
};
}
componentDidMount() {
const wordPressSiteUrl = "http://localhost/wordpress";
console.warn(this.props.id);
this.setState({ loading: true }, () => {
axios
.get(`${wordPressSiteUrl}/wp-json/acf/v3/property/${this.props.id}`)
.then((res) => {
this.setState({ loading: false, post: res.data });
})
.catch((error) =>
this.setState({ loading: false, error: error.response.data })
);
// console.log(this.props.id);
});
}
render() {
const { post, error, loading } = this.state;
return (
<div>
{Object.keys(post).length ? (
<div className="post-container">
<div key={post.id} className="card">
<div className="card-header">{post.acf.property_title}</div>
<div className="card-img-top">
<img src={post.acf.featured_image.url} alt="" />
{console.log(post.id)}
</div>
</div>
</div>
) : (
""
)}
</div>
);
}
}
export default SinglePost;
App.js
import React from "react";
import Home from "./components/Home";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import SinglePost from "./components/SinglePost";
import Navbar from "./components/Navbar";
function App() {
return (
<div className="App">
<BrowserRouter>
<Navbar />
<Routes>
<Route path="/" element={<Home />} />
<Route path="/property/:id" element={<SinglePost />} />
</Routes>
</BrowserRouter>
</div>
);
}
export default App;

How to get a detailed overview of some articles

import React from 'react';
import axios from 'axios';
import { Card } from 'antd';
class ArticleDetail extends React.Component {
state = {
article: {}
}
componentDidMount() {
const articleID = this.props.match.params.articleID;
axios.get(`http://127.0.0.1:8000/api/${articleID}`)
.then(res => {
this.setState({
article: res.data
});
})
}
render() {
return (
<div>
<Card title={this.state.article.title}>
<p>{this.state.article.content}</p>
</Card>
</div>
)
}
}
export default ArticleDetail;
//Make sure on your article.js file under title link you use ` instead of '
<List.Item.Meta
avatar={<Avatar src={item.avatar} />}
title={<a href={`/${item.id}`}>{item.title}</a>} //here
description={item.description}
/>
{item.content}
</List.Item>`
//And under your routes.js file make sure the (article Id) is the same as the one you used on the Article-detail-view
exact path='/:articleID' component={ArticleDetail}

Extract Data from API and show in another page

This question may sound silly to some people, but I am really confused on how to do it
I have 3 file: App.js, HomePage.js and Profile.js
App.js :
import React from "react"
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import HomePage from "./components/HomePage";
import Profile from "./components/Profile"
function App() {
return (
<Router>
<Switch>
<Route path="/" exact component={HomePage} />
<Route exact path="/profile/:profileId" component= {Profile} />
</Switch>
</Router>
);
}
export default App;
From here, the default page it will go to is HomePage.js
HomePage.js:
import React, { Component } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
class HomePage extends Component {
constructor() {
super();
this.state = {
userData: [],
}
}
componentDidMount() {
axios.get("XXXXXXXX").then((response) => {
const userDataList = response.data.users;
this.setState({
userData: userDataList
})
})
}
render() {
const userGrid = this.state.userData.map((user, index) => {
return (
<div key={index}>
<Link to={`/profile/${user.id}`}>
<img src={user.profilepicture} />
<p>{user.name}</p>
</Link>
</div>
)
})
return (
<div className="App">
<div className="card">
<div className="card__top">
<span className="card__title">
<p>Select An Account</p>
</span>
</div>
<div className="card__bottom">
<div className="card__table">
{userGrid}
</div>
</div>
</div>
</div>
)
}
}
export default HomePage;
In HomePage.js, I am able to show the profile picture and name of the user from API.
In the next page which is Profile.js , I am able to print the ID of the user.
Profile.js:
import React, { Component } from "react";
class Profile extends Component{
componentDidMount(){
const uid = this.props.match.params.profileId;
}
render() {
console.log(this.props.match);
return(
<h1>{this.props.match.params.profileId}</h1>
)
}
}
export default Profile;
As you can see I am printing the ID of user.
Here I also want to show the Profile Picture of the user which I selected in HomePage.js
This I am not able to do it.
JSON file:
{ - users: [-{id:1, name:"abc", profilepicture: "xxxxx.jpeg"}, ]}
You need to store a global state in your applicattion, which you can access from every connected component. This is a more complex topic. redux is a good framework to handle your global state changes.
Here is a tutorial: https://appdividend.com/2018/06/14/how-to-connect-react-and-redux-with-example/
I found it pretty hard to learn redux, but in the end it takes away a lot of pain. Because this is a problem you gonna have in every app you build with react.
You need use Context API o redux
Example context API: https://ibaslogic.com/react-context-api/
Context's well to little projects, but Redux performs better.
App.js
import React from "react"
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import HomePage from "./components/HomePage";
import Profile from "./components/Profile"
import { UsersProvider } from "./UsersProvider.js";
function App() {
return (
<Router>
<UsersProvider>
<Switch>
<Route path="/" exact component={HomePage} />
<Route exact path="/profile/:profileId" component= {Profile} />
</Switch>
</UsersProvider>
</Router>
);
}
export default App;
UsersContext.js
import React, { Component } from "react"
const UsersContext = React.createContext();
const UsersProvider = UsersContext.Provider;
const UsersConsumer = TodosContext.Consumer;
class MyContext extends Component {
state = {
value: null,
};
setValue = (value) => {
this.setState({ value });
};
render() {
return (
<UsersProvider value={{ setValue, value }}>{this.props.children}
</UsersProvider>
)
}
}
export { UsersContext, UsersProvider, UsersConsumer }
HomePage.js
import React, { Component } from "react";
import axios from 'axios';
class HomePage extends Component {
componentDidMount() {
axios.get("XXXXXXXX").then((response) => {
const userDataList = response.data.users;
// updating your context
this.props.context.setValue(userDataList);
})
}
render() {
const userGrid = this.props.context.value.map((user, index) => {
return (
<div key={index}>
<Link to={`/profile/${user.id}`}>
<img src={user.profilepicture} />
<p>{user.name}</p>
</Link>
</div>
)
})
return (
<div className="App">
<div className="card">
<div className="card__top">
<span className="card__title">
<p>Select An Account</p>
</span>
</div>
<div className="card__bottom">
<div className="card__table">
{userGrid}
</div>
</div>
</div>
</div>
)
}
}
export default HomePage;
Profile.js
import React, { Component } from "react";
import { UsersConsumer } from "./UsersContext.js";
class Profile extends Component{
render() {
return(
<UsersConsumer>
{users => (
<h1>{users.value.find(user => user.id === this.props.match.params.profileId)}</h1>
)}
</UsersConsumer>
)
}
}
export default Profile;

Not able to open screen in reactjs.Routing not working

I am new to react and trying below link to get started.
https://jasonwatmore.com/post/2018/09/11/react-basic-http-authentication-tutorial-example
But, my screen is not showing any thing and there is not such error on CLI after npm start.
Below is index.js.
import React from 'react';
import { render } from 'react-dom';
import { App } from './App/App.js';
// setup fake backend
import { configureFakeBackend } from './_helpers/fake-backend.js';
configureFakeBackend();
render(
<App />,
document.getElementById('app')
);
App.js
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import { PrivateRoute } from '../_components/PrivateRoute.js';
import { HomePage } from '../HomePage/Homepage.js';
import { LoginPage } from '../LoginPage';
class App extends React.Component {
render() {
return (
<div className="jumbotron">
<div className="container">
<div className="col-sm-8 col-sm-offset-2">
<Router>
<div>
<PrivateRoute path="/" exact component={HomePage} />
<Route path="/login" exact component={LoginPage} />
</div>
</Router>
</div>
</div>
</div>
);
}
}
export { App };
It is just opening a blank half opened screen.
Below is CLI screen shot.
Below are home and login.js code.
import React from 'react';
import { Link } from 'react-router-dom';
import { userService } from '../_services/user.service.js';
class HomePage extends React.Component {
constructor(props) {
super(props);
this.state = {
user: {},
users: []
};
}
componentDidMount() {
this.setState({
user: JSON.parse(localStorage.getItem('user')),
users: { loading: true }
});
userService.getAll().then(users => this.setState({ users }));
}
render() {
const { user, users } = this.state;
return (
<div className="col-md-6 col-md-offset-3">
alert("I am 2nd here");
<h1 >Hi {user.firstName}!</h1>
<p>You're logged in with React & Basic HTTP Authentication!!</p>
<h3>Users from secure api end point:</h3>
{users.loading && <em>Loading users...</em>}
{users.length &&
<ul>
{users.map((user, index) =>
<li key={user.id}>
{user.firstName + ' ' + user.lastName}
</li>
)}
</ul>
}
<p>
<Link to="/login">Logout</Link>
</p>
</div>
);
}
}
export { HomePage };
And output screen is :

Show search result component in another route

I am working with the MovieDB API. I want to show now playing movies on the root route but search result in another route.
I have tried putting history.push() method in handlesubmit but it shows error. Here's the code. Currently I am showing search result component in the home page itself.
App.js
import React, { Component } from "react";
import "./App.css";
import { BrowserRouter, Link, Switch, Route } from "react-router-dom";
import Nav from "./component/Nav";
import axios from "axios";
import { Provider } from "./context";
import Home from "./component/Home";
import SearchResult from "./component/SearchResult";
import MovieDetails from "./component/movieDetails";
class App extends Component {
state = {
movieList: [],
searchResult: [],
currentpage: 1,
totalpage: 1,
API_KEY: "c51081c224217a3989b0bc0c4b3d3fff"
};
componentDidMount() {
this.getCurrentMovies();
}
getCurrentMovies = e => {
axios
.get(
`https://api.themoviedb.org/3/movie/now_playing?api_key=${
this.state.API_KEY
}&language=en-US&page=${this.state.currentpage}`
)
.then(res => {
this.setState({
movieList: res.data.results,
currentpage: res.data.page,
totalpage: res.data.total_pages
});
console.log(this.state);
});
};
getMovies = e => {
e.preventDefault();
const moviename = e.target.elements.moviename.value;
axios
.get(
`https://api.themoviedb.org/3/search/movie?api_key=${
this.state.API_KEY
}&query=${moviename}`
)
.then(res => {
this.setState({
searchResult: res.data.results
});
console.log(this.state.searchResult);
});
console.log(this.router);
};
nextPage = () => {
this.setState(
{
currentpage: (this.state.currentpage += 1)
},
() => console.log(this.state.currentpage)
);
this.getCurrentMovies();
};
prevPage = () => {
if (this.state.movieList && this.state.currentpage !== 1) {
this.setState(
{
currentpage: (this.state.currentpage -= 1)
},
() => console.log(this.state.currentpage)
);
this.getCurrentMovies();
}
};
render() {
const contextProps = {
myState: this.state,
getMovies: this.getMovies,
nextPage: this.nextPage,
prevPage: this.prevPage,
};
return (
<Provider value={contextProps}>
<BrowserRouter>
<Nav />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/:id" component={MovieDetails} />
</Switch>
</BrowserRouter>
</Provider>
);
}
}
export default App;
Home.js
import React, { Component } from "react";
import NowPlaying from "./NowPlaying";
import SearchResult from "./SearchResult";
import SearchBox from "./SearchBox";
class Home extends Component {
state = {};
render() {
return (
<div>
<SearchBox />
<SearchResult />
<NowPlaying />
</div>
);
}
}
export default Home;
SearchBox.js
import React, { Component } from "react";
import { MyContext } from "../context";
import { withRouter } from "react-router-dom";
class SearchBox extends Component {
static contextType = MyContext;
render() {
return (
<React.Fragment>
<div className="jumbotron jumbotron-fluid">
<div className="container" style={{ textAlign: "center" }}>
<h1 className="display-4">Find your Movie</h1>
<p className="lead">
Find rating, descrips and much more of your fev. movie.
</p>
<form onSubmit={this.context.getMovies}>
<input
name="moviename"
className="form-control mr-sm-2"
type="search, submit"
placeholder="Search"
aria-label="Search"
style={{ height: "50px" }}
/>
</form>
</div>
</div>
<div />
</React.Fragment>
);
}
}
export default withRouter(SearchBox);
SearchResult.js
import React, { Component } from "react";
import Movie from "./movie";
import { withRouter } from "react-router-dom";
import { MyContext } from "../context";
import SearchBox from "./SearchBox";
class SearchResult extends Component {
static contextType = MyContext;
render() {
return (
<React.Fragment>
<div className="container">
<div className="row justify-content-center">
{this.context.myState.searchResult.map(movie => {
return <Movie id={movie.id} image={movie.poster_path} />;
})}
</div>
{/* <button>Prev</button>
<button>Next</button> */}
</div>
</React.Fragment>
);
}
}
export default SearchResult;
and another thing. The pagination works for Now Playing Movies but couldn't make it to work with search result. Please help.
You can pass data with Redirect like this:
<Redirect to={{
pathname: '/movies',
state: { id: '123' }
}}
/>
and this is how you can access it:
this.props.location.state.id

Resources