React implementing react-sticky - reactjs

I am trying to implement the following: https://www.npmjs.com/package/react-sticky
in my code as follow:
import React from 'react';
import Video from './../video.jsx';
import Overview from './overview.jsx';
import Photography from './photography.jsx';
import Details from './details.jsx';
import Cast from './cast.jsx';
import porgectsCollection from './../../data/projectInfo.js';
import { StickyContainer, Sticky } from 'react-sticky';
class Nav extends React.Component {
constructor(props) {
super(props);
this.state = {
mobileMenu: false
};
}
showMobileMenu () {
this.setState({ mobileMenu: !this.state.mobileMenu });
}
render () {
let links = this.props.project.links.map(function(el, i){
return <li key={i}>{el}</li>;
});
const open = this.state.mobileMenu ? ' open' : '';
return (
<StickyContainer>
<span onClick={this.showMobileMenu.bind(this)} className="mobile-trigger">X</span>
<Sticky topOffset={100} stickyClassName="sticky-nav">
<nav className={"secondary-nav" + open}>
<ul>
{links}
</ul>
</nav>
</Sticky>
</StickyContainer>
);
}
}
class SingleProject extends React.Component {
getProjectDataFromUrl() {
return porgectsCollection.filter(el => el.title === this.props.params.id);
}
render () {
let data = this.getProjectDataFromUrl(),
project = data[0];
console.log(project);
return (
<section className="project-page">
<Video project={project} />
<Nav project={project} />
<Overview project={project} />
<Photography project={project} />
<Details project={project} />
<Cast project={project} />
</section>
);
}
}
export default SingleProject;
I would hope that when "Sticky" reached 100px from the top it would get a custom class "sticky-nav" applied to it. However the nav keeps on scrolling without getting stuck at all. I can see the divs applied around my markup with the extra padding but no more then that.
URL project: https://github.com/WebTerminator/aldemar,
file in question is singleProject.jsx

import React from 'react';
import Video from './../video.jsx';
import Overview from './overview.jsx';
import Photography from './photography.jsx';
import Details from './details.jsx';
import Cast from './cast.jsx';
import porgectsCollection from './../../data/projectInfo.js';
import { StickyContainer, Sticky } from 'react-sticky';
class Nav extends React.Component {
constructor(props) {
super(props);
this.state = {
mobileMenu: false
};
}
showMobileMenu () {
this.setState({ mobileMenu: !this.state.mobileMenu });
}
render () {
let links = this.props.project.links.map(function(el, i){
return <li key={i}>{el}</li>;
});
const open = this.state.mobileMenu ? ' open' : '';
return (
<Sticky stickyClassName="sticky-nav" topOffset={-100}>
<span onClick={this.showMobileMenu.bind(this)} className="mobile-trigger">X</span>
<nav className={"secondary-nav" + open}>
<ul>
{links}
</ul>
</nav>
</Sticky>
);
}
}
class SingleProject extends React.Component {
getProjectDataFromUrl() {
return porgectsCollection.filter(el => el.title === this.props.params.id);
}
render () {
let data = this.getProjectDataFromUrl(),
project = data[0];
return (
<section className="project-page">
<StickyContainer>
<Video project={project} />
<Nav project={project} />
<Overview project={project} />
<Photography project={project} />
<Details project={project} />
<Cast project={project} />
</StickyContainer>
</section>
);
}
}
export default SingleProject;

Related

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

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 };

Getting null when invoking sibling component function

I am implementing a scrolling functionality on the same page when the Contact Us button is clicked. The Contact Us is contained in a child component (MyNavbar); when clicked, it will scroll to a fragment contained in another child component (MyContactForm), which is sibling of MyNavbar.
Here's the parent component:
// App.js
import React, { Component } from 'react';
import MyNavbar from './components/MyNavbar';
import MyContactForm from './components/MyContactForm';
export default class App extends Component {
constructor(props) {
super(props);
...
}
scrollToContactForm = () => {
this.refs.contactForm.scrollTo();
}
render() {
return (
<main>
<MyNavbar onClickToContactUs={ () => this.scrollToContactForm() } />
<MyContactForm ref="contactForm" />
</main>
);
}
}
And here are the two child components, MyNavbar
// MyNavbar.js
import React, { useState } from 'react';
import { Navbar, Nav, NavItem, NavLink } from 'reactstrap';
const MyNavbar = (props) => {
return (
<Navbar>
<Nav>
...
<NavItem>
<NavLink href="/products/"> Products </NavLink>
</NavItem>
<NavItem>
<NavLink href="/services/"> Services </NavLink>
</NavItem>
<NavItem>
<NavLink onClick={ () => props.onClickToContactUs() } href="#"> Contact Us </NavLink>
</NavItem>
</Nav>
</Navbar>
);
}
export default MyNavbar;
and MyContactForm:
// MyContactForm.js
import React, { Component } from 'react';
import { Form, ... } from 'reactstrap';
export default class MyContactForm extends Component {
constructor(props) {
super(props);
this.state = {
email: '',
...
inquiry: ''
};
this.setEmail = this.setEmail.bind(this);
...
this.setInquiry = this.setInquiry.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.myRef = React.createRef();
}
setEmail(event) {
this.setState( { email: event.target.email } );
}
...
setInquiry(event) {
this.setState( { question: event.target.inquiry } );
}
handleSubmit(event) {
alert("Thank you for contacting us. We will respond to you shortly");
event.preventDefault();
}
scrollTo = () => window.scrollTo(0, this.myRef.current.offsetTop);
render() {
return (
<React.Fragment ref={this.myRef} >
<Form onSubmit={this.handleSubmit}>
...
</Form>
</React.Fragment>
);
}
}
The app runs, however when I click Contact Us, I get a message saying
this.myRef.current is null
How can I get this to work?
Here's what worked for me:
I replaced <React.Fragment> with a <div>. Putting the ref in <Form> doesn't work either, as it should be on a DOM node (HTML element, not React component). So MyContactForm.js becomes:
render() {
return (
<div ref={this.myRef} >
<Form onSubmit={this.handleSubmit}>
...
</Form>
</div>
);
}

Toogle button not updating state properly

I have a button that I am using to toggle my sidebar in react application. The toggle button works fine for first two toggle states than it repeats the state twice for third time.
This is how I am toggling state from child component to parent:
import React, { Component } from 'react'
export default class Header extends Component {
constructor(props) {
super(props)
this.state = {
toggle: false
}
}
toggleSidebar = () => {
this.setState({
toggle : !this.state.toggle
});
console.log(this.state.toggle)
this.props.getToggleState(this.state.toggle);
}
render() {
return (
<div>
<button style={{width: '60px'}} onClick={this.toggleSidebar}>Toogle</button>
</div>
)
}
}
export default class App extends Component{
constructor(props) {
super(props)
this.state = {
toggleVal:''
}
}
getData = (val) => {
this.setState({
toggleVal: val
})
}
render(){
let toggleConst = '';
if(this.state.toggleVal){
toggleConst = (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData}/>
<Routes/>
<Footer/>
</div>
</div>
</Router>
)
}
else{
toggleConst = (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<SideNav toggleVal={this.state.toggleVal}/>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData}/>
<Routes/>
<Footer/>
</div>
</div>
</Router>
)
}
return (
toggleConst
);
}
}
Toggling the button hides/open the sidebar perfectly but it stuck on state when gets 'false' as twice.
This is how state console goes:
I am not able to find the problem here. Any help appreciated.
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router} from "react-router-dom";
import Header from './Header';
import Sidebar from './Sidebar'
export default class App extends Component{
constructor(props) {
super(props)
this.state = {
toggleVal: false
}
}
getData = (val) => {
this.setState({
toggleVal: val
});
}
render(){
console.log("called.....123...",this.state.toggleVal)
if(this.state.toggleVal){
return (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<Sidebar toggleVal={this.state.toggleVal}/>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData} />
</div>
</div>
</Router>
)
}
else{
return (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection:'row'}}>
<Sidebar toggleVal={this.state.toggleVal}/>
<div style={{flexDirection:'column'}}>
<Header getToggleState={this.getData}/>
</div>
</div>
</Router>
)
}
}
}
Header.js
import React, { Component } from 'react'
export default class Header extends Component {
constructor(props) {
super(props)
this.state = {
toggle: false
}
}
toggleSidebar = () => {
this.setState({
toggle: !this.state.toggle
},()=>{
// console.log(this.state.toggle)
this.props.getToggleState(this.state.toggle);
});
}
render() {
return (
<div>
<button onClick={()=>this.toggleSidebar(this.state.toggle)}>Toogle</button>
</div>
)
}
}
Sidebar.js
import React, { Component } from 'react'
import { NavLink } from "react-router-dom";
export default class Sidebar extends Component {
render() {
return (
<>
{
this.props.toggleVal &&
<div className="sidebar_container">
<nav className="nav_container">
<ul>
<li>
<NavLink to="/" activeClassName="active" exact={true}>Dashboard</NavLink>
</li>
<li>
<NavLink to="/user" activeClassName="active">User PRofile</NavLink>
</li>
<li>
<NavLink to="/register" activeClassName="active">Register</NavLink>
</li>
</ul>
</nav>
</div>
}
</>
)
}
}
https://repl.it/repls/IncredibleLinedCgi
This Will Work for You
Change this part of the code:
this.setState({
toggle : !this.state.toggle
});
To this:
this.setState(prev => {
return { toggle : !prev.toggle }
});
You should call getToggleState inside your setState callback in order to use proper state as argument
this.setState(prevState => {
this.props.getToggleState(!prevState.toggle);
return { toggle: !prevState.toggle };
});
Despite this solution, it's better if you don't keep duplicate state in child component <Header /> as conditional render is Parent duty.
This could be much simpler in my opinion.
Define the state on the parent component App ìsToggled
Call from the child component Header via callback this.props.onToggle()
Use conditional rendering on parent component {this.state.isToggled && <Sidebar/>}
import React, {Component} from 'react';
import {BrowserRouter as Router} from "react-router-dom";
import Header from './Header';
import Sidebar from './Sidebar'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isToggled: false
}
};
onToggle = () => {
this.setState({
isToggled: !this.state.isToggled
});
console.log(this.state.isToggled);
};
render() {
return (
<Router>
<div style={{display: 'flex', backgroundColor: '#ccc', height: '100%', flexDirection: 'row'}}>
<div style={{flexDirection: 'column'}}>
<Header onToggle={this.onToggle}/>
</div>
{this.state.isToggled && <Sidebar/>}
</div>
</Router>
)
}
}
import React, {Component} from 'react'
export default class Header extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<button onClick={() => {
this.props.onToggle()
}}>Toggle
</button>
</div>
)
}
}
import React, {Component} from 'react'
import {NavLink} from "react-router-dom";
export default class Sidebar extends Component {
render() {
return (
<div className="sidebar_container">
<nav className="nav_container">
<ul>
<li>
<NavLink to="/" activeClassName="active" exact={true}>Dashboard</NavLink>
</li>
<li>
<NavLink to="/user" activeClassName="active">User PRofile</NavLink>
</li>
<li>
<NavLink to="/register" activeClassName="active">Register</NavLink>
</li>
</ul>
</nav>
</div>
)
}
}

I can declare a method Meteor onLogout within a constant?

I can declare a method within a constant, I try to implement the onLogout method in the navbar but I get an error in the method by saying 'js [;] expected' or require declaring the class in this way:
export default class Landing extends React.Component
import React from 'react';
import {Link} from 'react-router'
import { Accounts } from 'meteor/accounts-base';
const NavbarLanding = () => {
onLogout() {
Meteor.logout();
};
return (
<div className="navbar-landing">
<nav>
<div>
<ul className="ul-landing">
<img src="/images/fly_paper.svg"></img>
<li className="navbar-title"><a>Landing</a></li>
{/* <img border="0" height="40" hspace="0" src="/images/fly_paper.png" width="80" /> */}
{/* onClick={this.onLogout.bind(this) */}
{/* btn-primary */}
<div className="navbar-menu">
<li><a>acerca</a></li>
<li><a>portafolio</a></li>
<li><a>contacto</a></li>
<button className="btn"onClick={this.onLogout.bind(this)}>Logout</button>
</div>
</ul>
</div>
</nav>
</div>
);
};
export default NavbarLanding;
NavbarLanding.reactProptype = {
title: React.PropTypes.string.isRequired
};
You made an error declaring your component, it should be like this:
export default class NavbarLanding extends React.Component {
onLogout() {
Meteor.logout();
}
render() {
return (
// your html here
);
}
};
NavbarLanding.reactProptype = {
title: React.PropTypes.string.isRequired
};

access state of react component from other component

I have the following spinner
import React, { Component } from 'react'
import './Spinner.scss'
export default class Spinner extends Component {
constructor(props) {
super(props);
this.state = {showLoading: true};
}
render () {
return (
<div className="spinner">
<div className="double-bounce1"></div>
<div className="double-bounce2"></div>
</div>
)
}
}
and from other component I would like to show or hide this spinner here is the code of the component:
import React, { Component } from 'react'
import RTable from '../../../components/RTable/RTable'
import Spinner from '../../../components/Spinner/Spinner'
import CsvDownload from '../containers/CsvDownloadContainer'
export default class Table extends Component {
_renderBreadcrumb () {
const { breadcrumb, handleBreadcrumbClick } = this.props
return (
<ol className="breadcrumb">
{(breadcrumb || []).map(el => {
return (
<li key={el.datasetKey}>
<a onClick={() => { handleBreadcrumbClick(el.granularity, el.datasetKey, el.datasetKeyHuman) }}>
{el.datasetKeyHuman}
</a>
</li>
)
})}
</ol>
)
}
render () {
const { datasetRows, columns, metadata, showLoading } = this.props
return (
<div className="row">
<div className="col-sm-12">
{this._renderBreadcrumb()}
<RTable rows={datasetRows} columns={columns} metadata={metadata} />
{ this.props.showLoading ? <Spinner /> : null }
<CsvDownload />
</div>
</div>
)
}
}
as you can see I trying to show or hide the spinner using:
{ this.props.showLoading ? <Spinner /> : null }
but I'm always getting undefinde. Some help please.
You have to move this
constructor(props) {
super(props);
this.state = {showLoading: true};
}
to your <Table /> component, otherwise you access showLoading from <Table />'s props, but it is not passed from anywhere.
Then change also
{ this.props.showLoading ? <Spinner /> : null }
to
{ this.state.showLoading ? <Spinner /> : null }
To show / hide <Spinner /> just call this.setState({ showLoading: Boolean }) in your <Table /> component.

Resources