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 :
Related
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 };
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;
G'day
Following the tutorials in the older versions of React I have this in
my routes
<Route path="/people" component={People} />
<Route path="/people_new" component={CreatePeople} />
<Route path="/people/:email" component={ShowPeople} />
<Route path="/people_edit/:email" component={EditPeople} />
I have been implementing an upgrade to 16. The ShowPeople is not being called. Is this a change in the routing?
More code
people.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { apiGetData } from '../actions/api'; // our home spun API
import { FETCH_PEOPLE } from '../actions/api';
const API_KEY = ''; // not needed at the moment. reminder.
const URL = 'people';
//----------------------------
class People extends Component {
//--------------------
componentWillMount() {
const url = `${URL}${API_KEY}`; // target URI will fetch ALL entries
console.log('In people.js URL == ');
console.log(url);
this.props.apiGetData(FETCH_PEOPLE, url); // call the API
}
//-------------
renderPeople() {
console.log('In renderPeople :', this.props.people);
return this.props.people.map((person) => {
return(
<li className="list-group-item" key={person.id}>
<Link to={"/people/" + person.email}>
<strong>{person.name}</strong>
<span className="pull-right">{person.surname}</span>
</Link>
</li>
);
});
}
//--------
render() {
console.log('made it into People');
return(
<div>
<div className="jumbotron">
<h2>Asset-IQ - Live Build - May 2017</h2>
<h2>List of People</h2>
</div>
<div className="text-right">
<Link to="/people_new" className="btn btn-primary">
New Person
</Link>
</div>
<div>
<ul className="list-group">
{this.renderPeople()}
</ul>
</div>
</div>
);
}
}
//-------------------------------
function mapStateToProps(state) {
return { people: state.people.all };
}
//------------------------------------------------------------------------
export default connect(mapStateToProps, {apiGetData: apiGetData })(People);
//--------------------- EOF ---------------------------------------------
I was running a VERY early versionof React that came with a boilerplate
I got from a Udemy course. I didn't realise until a few weeks ago I was
running 0.9x!
The app is only half written so now is a good time to join this century.
Here is the component that USED to be rendered
// vim: set expandtab tabstop=4 shiftwidth=4 autoindent:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { apiGetData } from '../actions/api';
import { apiDeleteData } from '../actions/api';
import { FETCH_PERSON } from '../actions/api';
import { DELETE_PERSON } from '../actions/api';
//--------------------------------
class ShowPeople extends Component {
//--------------------
componentDidMount() {
const target = `people/${this.props.match.params.email}`; // email is the id passed in as a prop
console.log(target); // quick look at the value
this.props.apiGetData(FETCH_PERSON, target); // get the record from Python
}
//---------------
onDeleteClick() {
const target = `${this.props.match.params.email}`;
let ok = confirm("Sure you want to ZAP this mofo?");
if (ok) {
this.props.apiDeleteData(DELETE_PERSON, target).then(() =>
alert("They gone...."));
}
//browserHistory.push('/people'); HOW do we do this in React 16
}
//--------
render() {
const { person } = this.props;
console.log("In person");
console.log(person);
if (!person) {
return (
<div>
SPINNER....
</div>
);
}
//------
return (
<div>
<div className="jumbotron">
<h2>Asset-IQ - Live Build - May 2017</h2>
<h2>Person Detail</h2>
</div>
<h2>{person.name} {person.surname}</h2>
<Link to="/people" className="btn btn-primary">Back</Link>
<button className="btn btn-warning pull-right" onClick={this.onDeleteClick.bind(this)}>
Delete
</button>
</div>
);
}
}
//--------------------------------
function mapStateToProps(state) {
return { person: state.people.person };
}
//-----------------------------------------------------------------------------------
export default connect(mapStateToProps, { apiGetData, apiDeleteData })(ShowPeople);
//--------------------- EOF ---------------------------------------------------
Cheers
You need to use the exact attribute in your routes to make it work correctly.
<Route path="/people" exact component={People} />
<Route path="/people_new" component={CreatePeople} />
<Route path="/people/:email" component={ShowPeople} />
<Route path="/people_edit/:email" component={EditPeople}
Here you have more detailed information about this attribute.
And here you have a live demo.
I am trying to add some functionality that enables or disables a button depending on whether the user has at least one "credit". I want to use the logical && to determine whether to enabled or disabled the button. The parent component fetches the current user asynchronously, which should give the component access to the user model and the users credits.
CHILD COMPONENT:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
import { connect } from 'react-redux';
import SurveyList from './surveys/SurveyList';
class Dashboard extends Component {
render() {
console.log(this.props);
return (
<div>
<SurveyList />
<div className="fixed-action-btn">
{this.props.auth.credits &&
<Link to="/surveys/new" className="btn-floating btn-large red">
<i className="material-icons">add</i>
</Link>
}
<button className="btn-floating btn-large disabled red">
<i className="material-icons">add</i>
</button>
</div>
</div>
);
}
};
function mapStateToProps(state) {
return {
auth: state.auth
}
}
export default connect(mapStateToProps)(Dashboard);
PARENT COMPONENT:
import React, { Component } from 'react';
import { BrowserRouter, Route } from 'react-router-dom';
import Header from './Header';
import { connect } from 'react-redux';
import * as actions from '../actions';
import Landing from './Landing';
import Dashboard from './Dashboard';
import NewList from './lists/NewList';
class App extends Component {
componentDidMount() {
this.props.fetchUser();
}
render() {
console.log(this.props);
return (
<div className="container">
<BrowserRouter>
<div>
<Header />
<Route exact path='/' component={Landing} />
<Route exact path='/surveys' component={Dashboard} />
<Route path='/surveys/new' component={NewList} />
</div>
</BrowserRouter>
</div>
);
}
};
export default connect(null, actions)(App);
ACTION:
export const fetchUser = () => async dispatch => {
const res = await axios.get('/api/currentUser')
dispatch({ type: FETCH_USER, payload: res.data});
};
Add an additional check this.props.auth && this.props.auth.credits &&...
This is my index.js page
import React from 'react';
import ReactDOM from 'react-dom';
import Login from './Login';
import Dashboard from './Dashboard';
import { BrowserRouter as Router, Route} from 'react-router-dom';
import './css/bootstrap.min.css';
import './css/font-awesome.min.css';
import './css/style.css';
import { createHistory, useBasename } from 'history'
const history = useBasename(createHistory)({
basename: '/'
})
ReactDOM.render((
<Router history={history}>
<div>
<Route path="/" component={Login} />
<Route path="dashboard" component={Dashboard} store={Dashboard} />
<Route exact path="login" component={Login} store={Login} />
</div>
</Router>
),
document.getElementById('root')
);
This is my login page. But clicking on the button doesn't redirect to the corresponding component.
import React, { Component } from 'react';
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
//this.props.router.push('/dashboard'); // Its was not working
this.props.history.push('dashboard'); //Its working for me
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In your case this.props.router would be undefined. Here's a rough solution that I made. Reading the comments in the code will help.
import React, { Component } from 'react';
import { Redirect } from 'react-router-dom'; // add this import
export default class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : '',
redirectToReferrer: true // when you're checking if the user is authenticated you have to keep this false
};
}
// componentWillReceiveProps(nextProps) {
// if ( put your authentication logic here ) {
// this.setState({ redirectToReferrer: true });
// }
// }
login(){
this.props.history.push('/dashboard');
}
render() {
const from = { pathname: '/dashboard' };
const { redirectToReferrer } = this.state; // redirectToReferrer is true in the initial state
if (redirectToReferrer) { // if true the user will be redirected to /dashboard
return <Redirect to={from} />;
}
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
In React 16 and above you can use Redirect from 'react-router-dom'
import { Redirect } from 'react-router-dom'
Define state in your component
this.state = {
loginStatus:true
}
than in your render method
render () {
if(this.state.loginStatus){
return <Redirect to='/home' />
}
return(
<div> Please Login </div>
)
}
Make use of withRouter frun react-router to inject router as a prop to your login component
import React, { Component } from 'react';
import {withRouter} from 'react-router'
import $ from 'jquery';
class Login extends Component {
constructor (props){
super(props);
this.state = {
email : '',
password : '',
userId : ''
};
}
login(){
this.props.history.push('/dashboard');
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-xl-12">
<div className="login-page-block-inner">
<div className="login-page-block-form">
<div className="form-actions">
<button type="button" className="btn btn-primary width-150" onClick={(e) => { this.login()} }>Sign In</button>
</div>
</div>
</div>
</div>
</div>
</div>
);
}
}
export default withRouter(Login)