How to pass the state of the page to other React? - javascript

I want to know how I can pass a status from one page to another page for if used in the other way.
My first page Body.js (Which I handle the state):
import React from 'react';
import './Body.css';
import axios from 'axios';
import { Link } from "react-router-dom";
import User from './User';
class Body extends React.Component {
constructor (){
super();
this.state ={
employee:[],
employeeCurrent:[],
}
}
componentDidMount(){
axios.get('http://127.0.0.1:3004/employee').then(
response=>this.setState({employee: response.data})
)
}
getName = () => {
const {employee} = this.state;
return employee.map(name=> <Link className='link' to={`/user/${name.name}`}> <div onClick={()=>this.add(name)} key={name.id} className='item'> <img className='img' src={`https://picsum.photos/${name.name}`}></img> <h1 className='name'> {name.name} </h1></div> </Link>)
}
add = (name) => {
const nam = name;
this.state.employeeCurrent.push(nam)
console.log(this.state.employeeCurrent)
}
render(){
return(
<div className='body'>
{this.getName()}
</div>
)
}
}
export default Body;
My second page which I want to get the state called employeeCurrent:
import React from 'react';
import Header from './Header';
import Body from './Body';
class User extends React.Component {
constructor (props){
super(props);
this.props ={
employeeCurrent:[],
}
}
render(){
return(
<div >
{this.props.employeeCurrent}
</div>
)
}
}
export default User;
I'm using the React Router, it looks like this:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './App.css';
import Home from './Home';
import User from './User';
const AppRouter = () => (
<Router>
<div className='router'>
<Route exact path="/" component={Home}/>
<Route path="/user/:id" component={User}/>
</div>
</Router>
);
export default AppRouter;
My project is:
Home page, where you have users, obtained from the API, all users have attributes (name, age, city and country). Saved in employeeCurrent variable:
What I want is: grab these attributes from the clicked user and play on the user page:
Someone would can help me PLEASE?????

Like I explained earlier, you need to lift the state up:
AppRouter (holds the state and passes it to children)
class AppRouter extends React.Component {
state = {
employeeCurrent: [],
employee: []
};
componentDidMount() {
axios
.get("http://127.0.0.1:3004/employee")
.then(response => this.setState({ employee: response.data }));
}
add = name => {
this.setState(prevState => {
const copy = prevState.employeeCurrent.slice();
copy.push(name);
return {
employeeCurrent: copy
};
});
};
render() {
return (
<Router>
<div className="router">
<Route
exact
path="/"
render={props => (
<Home
{...props}
add={this.add}
employee={this.state.employee}
currentEmployee={this.state.currentEmployee}
/>
)}
/>
<Route
path="/user/:id"
component={props => (
<User
{...props}
employee={this.state.employee}
currentEmployee={this.state.currentEmployee}
/>
)}
/>
</div>
</Router>
);
}
}
Body and User (receive parent state as props together with updater functions):
class Body extends React.Component {
getName = () => {
const { employee, add } = this.props;
return employee.map(name => (
<Link className="link" to={`/user/${name.name}`}>
{" "}
<div onClick={() => add(name)} key={name.id} className="item">
{" "}
<img
className="img"
src={`https://picsum.photos/${name.name}`}
/>{" "}
<h1 className="name"> {name.name} </h1>
</div>{" "}
</Link>
));
};
render() {
return <div className="body">{this.getName()}</div>;
}
}
class User extends React.Component {
render() {
// you will need to map employeeCurrent somehow
return <div>{this.props.employeeCurrent}</div>;
}
}

Related

Cannot route to required React Component using React-Router-DOM

I am trying to route to the component "Products" from my Homepage as per the product id from the item list from the Home Component. My page is getting routed to 'localhost:3000/id' but it is not getting the Products component. There are no errors that I faced. I fetched the data from the fake API and displayed the products on the home page. After clicking the product I want the page to route to "Product" component. The address is routing as expected but the component is not loading.
import React, { Component } from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import Products from "./Products";
interface Props {}
interface ResponseData {
id: number;
price: number;
description: string;
image: string;
}
interface State {
response: ResponseData[];
}
export default class Home extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
response: [],
};
}
getProductsData = async () => {
const apiResponse = await fetch("https://fakestoreapi.com/products");
console.log(apiResponse);
const responseData = await apiResponse.json();
this.setState({
response: responseData,
});
};
componentDidMount() {
this.getProductsData();
}
render() {
const { response } = this.state;
if (response.length === 0) {
return <div className="loader">Loading the items....... </div>;
}
return (
<div >
<div className="product-list">
{response.map((resp) => (
<Switch>
<Link className = "product-cards"
to={`${resp.id}`} >
<Route path={`${resp.id}`} component={Products}/>
<div className="product-cards">
<img src={resp.image} />
<div className="product-description">{resp.description}</div>
<div className="product-price">{resp.price}</div>
</div>
</Link>
</Switch>
))}
</div>
</div>
);
}
}
You probably need to replace your switch routes to App component and in this Home component just use a Link to redirect to the path you want.
function App() {
return (
<Switch>
<Route exact path="/" component={ Home } />
<Route path="/:id" component={ Products } />
</Switch>
);
}
Home component return should be something like this:
return (
<div className="product-list">
{response.map((resp) => (
<Link
className = "product-cards"
to={`/${resp.id}`}
>
<div className="product-cards">
<img src={resp.image} />
<div className="product-description">{resp.description}</div>
<div className="product-price">{resp.price}</div>
</div>
</Link>
))}
</div>
);

ReactJS - Issues about Dynamic Routes

I have these components. I want to turn every into a dynamic url. For example, when accessing in the browser, http://localhost:3000/houses/1 I want to appear the House 1.
The other things in the application are working fine. I just want to solve this problem of implementing dynamic routes.
The data is fetched from a json file
db.json file
[
{
"houseId": 1,
"name": "House 1",
"photos": [
"house1_001.jpg",
"house1_002.jpg",
"house1_003.jpg",
"house1_004.jpg"
]
},
{
"houseId": 2,
"name": "House 2",
"photos": [
"house2_001.jpg",
"house2_002.jpg",
"house2_003.jpg",
"house2_004.jpg"
]
},
{
"houseId": 3,
"name": "House 3",
"photos": [
"house3_001.jpg",
"house3_002.jpg",
"house3_003.jpg",
"house3_004.jpg"
]
}
]
Router Component
import React from 'react';
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
import App from './App'
import Intro from './Intro'
import Houses from './Houses'
import House from './House'
export default props => (
<Router>
<Route exact path='/' render={() => <App />} >
<Route exact path='/intro' render={() => <Intro />} />
<Route exact path='/houses' render={() => <Houses />} />
<Route exact path='/houses/:houseId' render={(props) => <House {...props} />} />
</Route>
</Router>
)
Houses Component
import React, { Component } from 'react'
import House from './House'
var data = require('./db.json');
class Houses extends Component {
constructor(props) {
super(props);
this.state = {
houses: []
};
}
componentDidMount() {
this.setState({
houses: data
})
}
render() {
const { houses } = this.state;
return (
<div className="content house">
{
houses.map((house, index) => {
return (
<div>
<House house={house} />
</div>
)
})
}
</div>
)
}
}
export default Houses
**House Component**
import React, { Component } from 'react';
class House extends Component {
constructor(props) {
super(props)
this.state = {
houseId: ""
}
}
componentDidMount() {
this.setState({
houseId: this.props.match.params.id
})
}
render() {
return (
<div>
<h3>{this.props.house.name}</h3>
<ul>
{this.props.house.photos.map((photo, index) => {
return (
<li><img src={`/images/${photo}`} /></li>
)
})
}
</ul>
</div>
)
}
}
export default House;
House component
import React, { Component } from 'react';
class House extends Component {
constructor(props) {
super(props)
this.state = {
houseId: ""
}
}
componentDidMount() {
this.setState({
houseId: this.props.match.params.id
})
}
render() {
return (
<div>
<h3>{this.props.house.name}</h3>
<ul>
{this.props.house.photos.map((photo, index) => {
return (
<li><img src={`/images/${photo}`} /></li>
)
})
}
</ul>
</div>
)
}
}
export default House;
Pass the json data to <House/> component and use the id to display the correct data.
import React, { Component } from 'react';
const data = require('./db.json');
class House extends Component {
constructor(props) {
super(props)
this.state = {
houses: data,
}
}
render() {
const houseId = this.props.match.params.houseId;
return (
<div>
<h3>{this.state.houses[houseId].name}</h3>
<ul>
{this.state.houses[houseId].photos.map((photo, index) => {
return (
<li><img src={`/images/${photo}`} /></li>
)
})
}
</ul>
</div>
)
}
}
export default House;
Create two components, one will be rendered in Houses and one will be render on house/1
// rendered inside Houses
class House extends Component {
render() {
return (
<div>
<h3>{this.props.house.name}</h3>
<ul>
{this.props.house.photos.map((photo, index) => {
return (
<li><img src={`/images/${photo}`} /></li>
)
})
}
</ul>
</div>
)
}
}
HouseInfo, which display data by query parameter
import React, { Component } from 'react';
const data = require('./db.json');
class HouseInfo extends Component {
constructor(props) {
super(props)
this.state = {
houses: data,
}
}
render() {
const id = this.props.match.params.houseId;
const houseId = id >= 1 ? id - 1 : 0;
return (
<div>
<h3>{this.state.houses[houseId].name}</h3>
<ul>
{this.state.houses[houseId].photos.map((photo, index) => {
return (
<li><img src={`/images/${photo}`} /></li>
)
})
}
</ul>
</div>
)
}
}
export default HouseInfo;
Router
import React from 'react';
import { BrowserRouter as Router, Route, NavLink } from 'react-router-dom'
import App from './App'
import Intro from './Intro'
import Houses from './Houses'
import House from './House'
import HouseInfo from './HouseInfo'
export default props => (
<Router>
<Route exact path='/' render={() => <App />} >
<Route exact path='/intro' render={() => <Intro />} />
<Route exact path='/houses' render={() => <Houses />} />
<Route exact path='/houses/:houseId' render={(props) => <HouseInfo {...props} />} />
</Route>
</Router>
)
Entire snippet is right except the thing is that you have wrongly matched the params id,
change the following code in house component
this.setState({
houseId: this.props.match.params.houseId
})
you have to use the same param id ie.,houseId inside the component
using the houseId in the state ie.,(this.state.houseId) in House component, loop through the json data and find the houseId and display the corresponding data.
I don't see what props you are passing to the House component but my guess is not exactly intended ones. Try this:
import { withRouter } from 'react-router-dom';
...
export default withRouter(Houses);
or without withRouter:
<Route exact path='/houses/:houseId' render={House} />
and in your Route your param value is specified as houseId, as it should be in House component:
this.setState({
houseId: this.props.match.params.houseId
})

React Router v4 Nested Routes pass in match with Class Component

I am trying to have a nested route in my application. Where a component is declared with class syntax.
How do I pass match?
As you can see below, I am using the componentDidMount() function to pull in data, so I need to have the member function and I want this component to handle all my logic.
import React, { Component } from 'react';
import ListItem from './ListItem';
import Post from './Post';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
//holds the state for all the components
//passes into listing
//listing will re-direct to proper post using router
export default class Blog extends Component {
constructor(props){
super(props);
this.state = {
articles: [],
content: null
};
}
storeData = (data) => {
const articles = data.map((post, index) => {
return {
key: index,
title: post.title.rendered,
content: post.content.rendered,
excerpt: post.excerpt.rendered,
slug: post.slug
};
});
this.setState(
{
articles: articles
}
);
};
componentDidMount() {
let articles = [];
fetch('https://XXXXX.com/posts/')
.then(data => data.json())
.then(this.storeData).catch(err => console.log(err));
}
render(){
return(
<div className="blog">
<h2> Listings </h2>
{ this.state.articles.map(post => (
<Link to= { `path/${post.slug}` } >
<ListItem
key={post.key}
title={post.title}
content={post.content}
/>
</Link>
))
}
<Route path='posts/:slug' component={Post} />
</div>
);
}
}
Found it out!
If you look below in render, it was saved as a this.props!
However, now it renders the component below rather than replace to another page.
render(){
return(
<div className="blog">
<h2> Listings </h2>
{ this.state.articles.map(post => (
<Link to={ `${this.props.match.url}/${post.slug}` } >
<ListItem
key={post.key}
title={post.title}
content={post.content}
/>
</Link>
))
}
<Route path={ `${this.props.match.path}/:slug` } component={Post} />
</div>
);
}
}

React Router: TypeError: render is not a function

Im working on this app and when I run npm start I keep getting this error "TypeError: render is not a function". Ive tired everything from deleting the dependencies to running npm install. I even update react-router-dom and react-dom several times. Im at a lost here.
Here is the GitHub to the repository
https://github.com/Drayz/My-Book-Reads-App.git
Here is the Code:
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter } from "react-router-dom";
import App from "./App";
import "./index.css";
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
); enter code here
App.js:
import React from 'react'
import { Switch,Route } from 'react-router-dom'
import Homepage from './windows/Homepage'
import Search from './windows/Search'
import Provider, {MyContext} from './Provider/'
import './App.css'
class BooksApp extends React.Component {
render() {
return (
<div className="app">
<Provider>
<MyContext.Consumer>
context
<Switch>
<Route exact path={"/"} render={ () => (
<MyContext.Consumer>
{context => <Homepage {...context} />}
</MyContext.Consumer>
)}/>
<Route exact path={"/search"} render={ () => (
<MyContext.Consumer>
{context => <Search {...context} />}
</MyContext.Consumer>
)}/>
</Switch>
</MyContext.Consumer>
</Provider>
</div>
)
}
}
export default BooksApp
Provider/index.js:
import React, { Component } from 'react';
export const MyContext = React.createContext();
export default class index extends Component {
constructor() {
super();
this.state ={
books:[],
currentlyReading:[],
wantToRead:[],
read:[],
addBooks: books => {
const currentlyReading = books.filter(book => book.shelf === 'currentlyReading');
const read = books.filter(book => book.shelf === 'read');
const wantToRead = books.filter(book => book.shelf ==='wantToRead');
this.setState({ books, currentlyReading, read, wantToRead });
},
moveBook: (book, newShelf, allShelfs) => {
console.log(newShelf);
const newBooks = this.state.books.map(allBooks => {
const foundID = allShelfs[newShelf].find(
bookID => bookID === allBooks.id
);
if (foundID) {
allBooks.shelf = newShelf;
}
return allBooks;
});
this.state.addBooks(newBooks);
}
};
}
render() {
return (
<MyContext.Provider value={{...this.state}}>
{this.props.children}
</MyContext.Provider>
)
}
}
SearchBook.js
import React, {Component} from 'react';
import {Link} from 'react-router-dom'
export default class Searchbooks extends Component {
render() {
return (
<div className="open-search">
<Link to={'/search'}>
Add a book
</Link>
</div>
)
}
}
Bookshelf.js
import React, {Component} from 'react';
import Book from './Book';
export default class Bookshelf extends Component {
render() {
return (
<div className="bookshelf">
<h2 className="bookshelf-title">{this.props.title}</h2>
<div className="bookshelf-books">
<ol className="books-grid">
{this.props.books &&
this.props.books.map(book => <Book key={book.id} {...book} moveBook={this.props.moveBook} />)}
</ol>
</div>
</div>
)
}
}
Book.js
import React, {Component} from "react";
import {update} from '../BooksAPI'
export default class Book extends Component {
handleChange = async e => {
e.presist()
try {
const shelf = e.target.value;
const book = this.props;
const result = await update(book, shelf);
this.props.moveBook(book, shelf, result);
} catch (error) {
console.log(error)
}
};
render() {
return (
<li>
<div className="book">
<div className="book-top">
<div className="book-cover"
style={{
width: 128,
height: 193,
backgroundImage:`url(${this.props.imageLinks ? this.props.imagesLinks.thumnail : ''})`
}}
/>
<div className="book-shelf-changer">
<select onChange={this.handleChange} value={this.props.shelf}>
<option value="move" disabled>Move to...</option>
<option value="currentlyReading">Currently Reading</option>
<option value="wantToRead">Want to Read</option>
<option value="read">Read</option>
<option value="none">None</option>
</select>
</div>
</div>
<div className="book-title">{this.props.title}</div>
<div className="book-authors">{this.props.authors ? this.props.author[0] : 'No Author'}</div>
</div>
</li>
)
}
}
Local_Host_Error, Local_Host_Error, Local_Host_Error
In App.js your consumer just says "context". I think what you meant was for that to be the variable that holds the data that comes from the provider. Right now it's just being read as a string and the render function freaks out because... well the logging isn't very good. In short when the component goes to render it hits a whole bunch of undefined and freaks out.
To fix this use:
{ context => {Your switch statement }}

The correct login page pattern

I am sorry for my stupid question but i am really new in react and this problem make me stuck for days. I am kinda confused to make a login page in reactjs. my app.js code is like this :
import React from 'react';
import {HashRouter as Router, Route} from 'react-router-dom';
import asyncComponent from './AsyncComponent';
import AppShell from './AppShell';
import Login from './login/Login';
const Dashboard = asyncComponent(() => {
return import(/* webpackChunkName: "dashboard" */ './dashboard/Dashboard')
.then(module => module.default);
});
const LoginPage = asyncComponent(() => {
return import(/* webpackChunkName: "login" */ './login/Login')
.then(module => module.default);
});
class App extends React.Component {
render() {
return (
<Router>
<AppShell>
<div>
<Route exact path="/" component={Dashboard} />
<Route path="/login" component={LoginPage} />
</div>
</AppShell>
</Router>
);
}
}
export default App;
And this is my AppShell code :
import React, {Component} from 'react';
import {Link} from 'react-router-dom';
import {MuiThemeProvider} from 'material-ui/styles';
import {AppBar, Drawer, MenuItem} from 'material-ui';
import {DashboardIcon} from './icon/Icons';
import ArrowDropRight from 'material-ui/svg-icons/navigation-arrow-drop-right';
const ContentStyle = {
width: '90%',
margin: 'auto',
marginTop: '30px'
};
class SidebarDrawer extends React.Component {
componentDidMount() {
let frameCount = 0;
const open = () => (frameCount++ > 0) ? this.props.onMounted() :
requestAnimationFrame(open);
requestAnimationFrame(open);
}
render() {
return (
<Drawer
docked={false}
width={200}
open={this.props.open}
onRequestChange={this.props.onRequestChange}
>
<MenuItem
primaryText={'Dashboard'}
leftIcon={<DashboardIcon/>}
containerElement={<Link to={'/'}/>}
onClick={this.props.onClick}
/>
</Drawer>
);
}
}
class AppShell extends Component {
constructor(props) {
super(props);
this.state = {
open: false,
drawer : false
};
}
handleDrawerToggle = (e) => {
if (!this.state.drawer) {
this.setState({drawer: true});
e.preventDefault();
} else {
this.setState({open: !this.state.open});
}
}
render() {
const LazySidebarDrawer = this.state.drawer && (<SidebarDrawer
open={this.state.open}
onMounted={() => this.setState({open: true})}
onClick={() => this.setState({open: false})}
onRequestChange={open => this.setState({open: open})}
/>)
return (
<MuiThemeProvider>
<div>
<AppBar
title="Dashboard"
iconClassNameRight="muidocs-icon-navigation-expand-more"
onLeftIconButtonTouchTap={this.handleDrawerToggle}
/>
{LazySidebarDrawer}
<div id="content" style={ContentStyle}>
{React.cloneElement(this.props.children)}
</div>
</div>
</MuiThemeProvider>
);
}
};
export default AppShell;
But i still can access dashboard when i open login page. How is the correct pattern for login page?
Thanks
Your routing is correct, the exact '/' will only render the Dashboard component when the path is '/'. What you're seeing is the dashboard drawer or AppBar component. The dashboard drawer is still there in the login screen because it's always there in the AppShell code and your routes are children of AppShell. A potential solution would be to move that AppBar component to your Dashboard component if you only want it there.

Categories

Resources