id of a specific react material tree-item - reactjs

I am using React Material TreeView, i am trying to create a route link that when i press on a TreeItem i can see it's specific details in the Outlet, but i dont know how to pass that ID of That specific item to the Outlet.
VesselComponents.js :
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchComponents } from "../../../features/componentsSlice";
import TreeItem from "#mui/lab/TreeItem";
import TreeView from "#mui/lab/TreeView";
import ExpandMoreIcon from "#mui/icons-material/ExpandMore";
import ChevronRightIcon from "#mui/icons-material/ChevronRight";
import { Link, Outlet } from "react-router-dom";
function VesselComponents() {
const { components, error, loading } = useSelector(
(state) => state.components
);
console.log(components);
const dispatch = useDispatch();
useEffect(() => {
fetchComponents()(dispatch);
}, [dispatch]);
const getTreeItemsFromData = (treeItems) => {
return treeItems.map((treeItemData) => {
let children = undefined;
if (treeItemData.children && treeItemData.children.length > 0) {
children = getTreeItemsFromData(treeItemData.children);
}
return (
<TreeItem
key={treeItemData.id}
nodeId={String(treeItemData.id)}
label={treeItemData.name}
children={children}
/>
);
});
};
const DataTreeView = ({ treeItems }) => {
return (
<TreeView
defaultCollapseIcon={<ExpandMoreIcon />}
defaultExpandIcon={<ChevronRightIcon />}
>
{getTreeItemsFromData(treeItems)}
</TreeView>
);
};
return (
<div className="components-container">
<div className="components-items">
{/* this line */}
<Link to={`./info/${components.id}`}>
<DataTreeView treeItems={components} />
</Link>
</div>
<div className="component-detail">
<Outlet />
</div>
</div>
);
}
export default VesselComponents;

Related

React - Share props between 2 components

I have a layout component that calls different components inside.
They are the header, breadcumbs , main and filter (sidebar left) and footer
I have a "filters" component that when selecting on the "select" I want it to send this information to the "categories" component.
That is, if in the component "filters" I filter by brand "FORD" I want the component "categories" to receive the brand "FORD"
The code like this works, but I can't pass the properties of the Filterheader component to the Name component (alias of category name)
Layout
import NavigationGuest from '#/components/Layouts/NavigationGuest'
import Footer from '#/components/Layouts/FooterGuest'
import { useRouter } from 'next/router'
import FilterHeader from "#/components/filters/Header";
const GuestLayout = ({ children }) => {
const router = useRouter()
return (
<div className="min-h-screen bg-gray-100">
<NavigationGuest />
<FilterHeaderNeveras />
{/* Page Content */}
<main>{children}</main>
<Footer />
</div>
)
}
export default GuestLayout
FilterHeader
import TextField from '#mui/material/TextField'
import Autocomplete from '#mui/material/Autocomplete'
import { useRouter } from 'next/router'
import { useState, useEffect } from 'react'
import axios from 'axios'
import Button from '#mui/material/Button'
const FilterHeaders = () => {
useRouter()
const [jsonResultBrands, setJsonResultBrands] = useState([])
const [selectMarca, setSelectMarca] = useState([])
const handleChangeBrand = (event, value) => {
setSelectMarca(value)
}
const handleButtonCLick = (event, value) => {
console.log(selectMarca)
}
useEffect(() => {
fetch(
'http://localhost:8000/api/productcategoryproperties/3/category/marca/type',
)
.then(response2 => response2.json())
.then(json2 => setJsonResultBrands(json2))
}, [])
return (
<div style={{ padding: '10px' }}>
<Autocomplete
onChange={handleChangeBrand }
disablePortal
id="combo-box-demo1"
key={jsonResultCalifEnergetica.id}
options={jsonResultBrands}
sx={{ width: '100%' }}
getOptionLabel={jsonResults => `${jsonResults.name}`}
renderInput={params => <TextField {...params} label="Brand" />}
/>
<Button variant="outlined" onClick={handleButtonCLick}>
Buscar
</Button>
</div>
)
}
export default FilterHeaders
Category Name
import Head from 'next/head'
import axios from 'axios'
import GuestLayout from '#/components/Layouts/GuestLayout'
import { useRouter } from 'next/router'
import Grid from '#mui/material/Grid'
import FilterHeaders from '#/components/filters/Header'
const Name = ({ itemsList }) => {
const router = useRouter()
return (
<GuestLayout>
<Head>
<title>Product Category {router.query.name}</title>
</Head>
<div className="py-12">
Filters: <br />
<FilterHeader />
</div>
</GuestLayout>
)
}
Name.getInitialProps = async () => {
const { data } = await axios.get('http://localhost:8080/api/category/1')
return { itemsList: data }
}
export default Name

products is not a function after destructuring

I have my homepage where I received the products with the redux method but I did not want to render them on the home page so I did it with a single product component, but again I wanted to display the products in react-Alice-carousel I sent the products in the homepage through props and destrusctured it in the Single product and tried to create the items props of react-alice-carousel through jsx but got an error product.map is not a function.
My Single Product Component.
import React from "react";
import AliceCarousel from "react-alice-carousel";
// import { Button, Card, Container } from "react-bootstrap";
// import { FaShoppingCart } from "react-icons/fa";
// import { useDispatch, useSelector } from "react-redux";
import { Link } from "react-router-dom";
// import { AddToCartAction, RemoveFromCart } from "../../actions/cartActions";
import UICARD from "../../interface/UICARD";
// import classes from "./home.module.css";
export function numberWithComas(x) {
return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
const SingleProduct = ({ product }) => {
const items = product.map((p) => {
return (
<Link to={`/product/${p._id}`}>
<UICARD>
<img src={p.image} alt={p.name} />
<span>
{p.name}
<span>{p.description}</span>
</span>
<span>{p.price}</span>
</UICARD>
</Link>
);
});
const responsive = {
0: {
items: 4,
},
512: {
items: 6,
},
};
return (
<div>
<AliceCarousel
items={items}
disableDotsControls
infinite
mouseTracking
responsive={responsive}
/>
</div>
);
};
export default SingleProduct;
My Home Page
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Products } from "../../actions/productsActions";
import ErrorMessage from "../../helpers/ErrorMessage";
import Loading from "../../helpers/Loading";
import SideBar from "../Home/SideBar";
import SingleProduct from "../Home/SingleProduct";
import classes from '../Home/home.module.css'
const Home = () => {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { products, error, loading } = productList
console.log(products);
useEffect(() => {
dispatch(Products());
},[dispatch])
return (
<div className ={classes.home}>
{error && <ErrorMessage variant={error.info?"info":"danger"}>{error}</ErrorMessage>}
{loading && <Loading />}
<SideBar />
<div className={classes.productContainer}>
{
products.map((product) => {
return <SingleProduct product={product} key={product._id} />
})
}
</div>
</div>
);
};
export default Home;
You need to change you home compoent like that since singleProduct need to have a props peroduct as an array , i recommand to use prop-types to avoid this kind of problems
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Products } from "../../actions/productsActions";
import ErrorMessage from "../../helpers/ErrorMessage";
import Loading from "../../helpers/Loading";
import SideBar from "../Home/SideBar";
import SingleProduct from "../Home/SingleProduct";
import classes from '../Home/home.module.css'
const Home = () => {
const dispatch = useDispatch();
const productList = useSelector((state) => state.productList);
const { products, error, loading } = productList
console.log(products);
useEffect(() => {
dispatch(Products());
},[dispatch])
return (
<div className ={classes.home}>
{error && <ErrorMessage variant={error.info?"info":"danger"}>{error}</ErrorMessage>}
{loading && <Loading />}
<SideBar />
<div className={classes.productContainer}>
<SingleProduct product={products} />
</div>
</div>
);
};
export default Home;

React router v5 Route tag not rendering enclosed component

I just started learning/working with react router and got stuck with the very basic stuff.
If I am adding the <Route> , the enclosed component is not loading. Can anyone please help me on this. I even tried removing other components and just testing with route but then also it was not working
index.js :
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import { Provider } from 'react-redux'
import store from './store/store'
import { BrowserRouter } from 'react-router-dom'
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Provider store={store}>
<App />
</Provider>
</BrowserRouter>
</React.StrictMode >,
document.getElementById('root')
);
App.js:
import './App.css';
import 'bootstrap/dist/css/bootstrap.css';
import 'bootstrap/dist/js/bootstrap.js';
import Header from './components/Header';
import ProductCard from './components/ProductCard';
import ProductPage from './components/ProductPage';
import Cart from './components/Cart';
import { useSelector } from 'react-redux';
import LoginForm from './components/LoginForm';
import { useState, useEffect } from 'react';
import { Route } from 'react-router-dom';
function App() {
const showCartOption = useSelector(state => state.cart.showCartOption);
const isAuthenticated = useSelector(state => state.auth.isAuthenticated);
return (
<div class="m-3 shadow p-2">
<Header></Header>
<div class="row" >
{(isAuthenticated && showCartOption) &&
<Route path="/products">
<ProductPage />
</Route>}
{(isAuthenticated && !showCartOption) &&
<Route path="/cart">
<Cart />
</Route>
}
{!isAuthenticated && <LoginForm></LoginForm>}
</div>
</div>
);
}
export default App;
ProductPage.js:
import { useEffect, useState } from "react";
import ProductCard from "./ProductCard";
function ProductPage() {
const [products, setProducts] = useState([]);
const productDescriptionLength = 75;
const productTitleLength = 15;
console.log("rendering : ");
console.log(products);
useEffect(() => {
console.log("fetching products");
const productResponse = fetch('https://fakestoreapi.com/products')
.then(res => {
return res.json();
})
.then(res => {
console.log("resolved response : ");
console.log(res);
const translatedResponse = res.map(product => {
return {
productId: product.id,
productTitle: product.title.substring(0, productTitleLength) + "...",
productPrice: product.price,
productDescription: product.description.substring(0, productDescriptionLength) + "...",
productImage: product.image
}
})
return translatedResponse;
})
.then(res => {
console.log(res);
setProducts(res);
});
}, [])
return (
<div className="row row-cols-1 row-cols-md-4 g-4">
{
products.length > 0 && products.map(product =>
<div class="col">
<ProductCard
productTitle={product.productTitle}
productPrice={product.productPrice}
productImage={product.productImage}
productDescription={product.productDescription}
/>
</div>
)
}
</div>
);
}
export default ProductPage;
cart.js:
import { useState } from "react";
import { useSelector } from "react-redux";
import CartCard from "./CartCard";
function Cart() {
const cartItems = useSelector(state => state.cart.cartItems);
console.log("cartItems : ");
console.log(cartItems);
return (
<div class="">
{cartItems.length === 0 && <p class="m-5 text-center fs-1 shadow">Your cart is empty. Happy Shopping !</p>}
{cartItems.length > 0 &&
cartItems.map(cartItem => {
return <CartCard
productTitle={cartItem.productTitle}
productPrice={cartItem.productPrice}
productDescription={cartItem.productDescription}>
</CartCard>
})
}
</div>
);
}
export default Cart;
I am able to see the navbar but none of the enclosed components in route
Your routes should be inside of a Switch component in react router v5.
Something like this:
function App() {
const showCartOption = useSelector((state) => state.cart.showCartOption);
const isAuthenticated = useSelector((state) => state.auth.isAuthenticated);
return (
<div class='m-3 shadow p-2'>
<Header></Header>
<div class='row'>
<Switch>
<Route path='/products'>
{isAuthenticated && showCartOption && <ProductPage />}
</Route>
<Route path='/cart'>
{isAuthenticated && !showCartOption && <Cart />}
</Route>
{!isAuthenticated && <LoginForm></LoginForm>}
</Switch>
</div>
</div>
);
}
Read the documentation.
https://v5.reactrouter.com/web/guides/quick-start

Unable to display an API data using map function on Material UI tabs

I'm new to this programming world. Can anyone please help me on this.
I have implemented Material UI's tabs successfully by hard-coding the content, but when I tried to make my hard coded tabs with a .map function to populate the content from a data source (json), it no longer works. The tab displays nothing.
Here are the codes,
Planet component:
import React from 'react';
function Planet(props) {
return (
<ul>
<li>{props.name}</li>
</ul>
);
}
export default Planet;
Planets component:
import React, { useEffect, useState} from 'react';
import Planet from './Planet';
function Planets(props) {
const [planets, setPlanets] = useState([]);
useEffect(() => {
getPlanets();
}, []);
const getPlanets = async () => {
const response = await fetch("https://assignment-machstatz.herokuapp.com/planet");
const data = await response.json();
setPlanets(data);
}
return (
<div>
{planets.map((planet, index) => {
return (
<Planet key={index} name={planet.name} />
);
})}
</div>
);
}
export default Planets;
App component:
import React, { useState } from 'react';
import { AppBar, Tabs, Tab } from '#material-ui/core';
import Planet from './Planet';
import Favplanets from './Favplanets';
function App() {
const [selectedTab, setSelectedTab] = useState(0);
function handleChange (event, newValue) {
setSelectedTab(newValue);
}
return (
<>
<AppBar position="static">
<Tabs value={selectedTab} onChange={handleChange} >
<Tab label="Planets" />
<Tab label="Favourite Planets" />
</Tabs>
</AppBar>
{selectedTab === 0 && <Planet />}
{selectedTab === 1 && <Favplanets />}
</>
);
}
export default App;
Thanks for your help!

React-Router-Dom <Link> not render page

I'm building a practice app that uses Unsplash to render users photos. I'm using React and Redux. With react-router-dom, I'm trying to follow the docs but I find it very confusing to set up. Here's what I have so far. When I click on a result out of a returned list of results from a search, I want it to render a user page profile.
index.js (make sure I have react-router-do set up correctly):
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
// import store from './app/store';
import { Provider } from 'react-redux';
import { createStore, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import reducers from "./app/reducers/rootReducer";
import * as serviceWorker from './serviceWorker';
const storeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(reducers, storeEnhancers(applyMiddleware(thunk)));
ReactDOM.render(
<React.StrictMode>
<Provider store={store}>
<BrowserRouter>
<App />
</BrowserRouter>
</Provider>
</React.StrictMode>,
document.getElementById("root")
);
Top component App
import React from "react";
import { BrowserRouter as Router, Route } from "react-router-dom";
import Images from "./app/components/Images";
import Search from "./app/components/Search";
import UserProfile from "./app/components/UserProfile";
import "./App.css";
function App() {
return (
<>
<Search />
<Images />
<Router>
<Route link="/userProfile">
<UserProfile />
</Route>
</Router>
</>
);
}
export default App;
search (parent component to searchResults where exists):
import React, { useState, useEffect } from "react";
import { connect } from "react-redux";
import { queryAction } from "../actions/queryAction";
import SearchResults from "./SearchResults";
const Search = (props) => {
const [query, setQuery] = useState("");
console.log(props.searches);
const searchPhotos = async (e) => {
e.preventDefault();
console.log("submitting form");
props.queryAction(query);
};
const showUsers = (user, e) => {
e.preventDefault()
console.log(user)
};
return (
<>
<form className="form" onSubmit={searchPhotos}>
<label className="label" htmlFor="query">
{" "}
</label>
<input
type="text"
name="query"
className="input"
placeholder={`Try "dog" or "apple"`}
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
<button type="submit" className="button">
Search
</button>
</form>
<SearchResults results={props.searches} showUsers={showUsers} />
</>
);
};
const mapStateToProps = (state) => {
return {
searches: state.searches,
};
};
const mapDispatchToProps = (dispatch) => {
return {
queryAction: (entry) => dispatch(queryAction(entry)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Search);
searchResults:
import React from "react";
import { BrowserRouter as Router, Link } from "react-router-dom";
import { getUserAction } from "../actions/getUserAction";
import { connect } from "react-redux";
const SearchResults = (props) => {
const { results } = props.results.searches;
const handleClick = (result, e) => {
e.preventDefault();
props.getUser(result.username);
};
return (
<>
{results &&
results.map((result, id) => {
return (
<div key={id}>
<Router>
<Link to="/userProfile" onClick={(e) => handleClick(result, e)}>
{result.username}
</Link>
</Router>
</div>
);
})}
</>
);
};
const mapDispatchToProps = (dispatch) => {
return {
getUser: (query) => dispatch(getUserAction(query)),
};
};
export default connect(null, mapDispatchToProps)(SearchResults);
and finally the UserProfile component:
import React from 'react';
import { connect } from 'react-redux';
const UserProfile = props => {
console.log(props)
return (
<div>
</div>
);
}
const mapStateToProps = state => {
return {
user: state.users
}
}
export default connect(mapStateToProps, null)(UserProfile);
app component
import React from "react";
import { Switch, Route } from "react-router-dom";
import Images from "./app/components/Images";
import Search from "./app/components/Search";
import UserProfile from "./app/components/UserProfile";
import "./App.css";
function App() {
return (
<>
<Search />
<Images />
<Switch>
<Route path="/userProfile/:username">
<UserProfile />
</Route>
</Switch>
</>
);
}
export default App;
SearchResults component
import React from "react";
import { Link } from "react-router-dom";
const SearchResults = (props) => {
const { results } = props.results.searches;
const handleClick = (result, e) => {
e.preventDefault();
props.getUser(result.username);
};
return (
<>
{results &&
results.map((result, id) => {
return (
<div key={id}>
<Link to={`/userProfile/${result.username}`}>
{result.username}
</Link>
</div>
);
})}
</>
);
};
export default SearchResults;
UserProfile component
import React, { useEffect } from 'react';
import { connect } from 'react-redux';
import { getUserAction } from "../actions/getUserAction";
const UserProfile = props => {
useEffect(() => {
props.getUserAction(props.match.params.username)
},[])
console.log(props)
return (
<div>
{props.user
? <div>{user.username}</div>
: <div>Loading...</div>
}
</div>
);
}
const mapStateToProps = state => {
return {
user: state.users
}
}
const mapDispatchToProps = (dispatch) => {
return {
getUser: (query) => dispatch(getUserAction(query)),
};
};
export default connect(mapStateToProps, mapDispatchToProps)(UserProfile);
Edit: Add a param to your link and remove the onclick. Update the Route to expect a :username param. You can access the param through props in UserProfile component.
Make sure to perform the action or access state when mounting the UserProfile component so you have some data when it renders.
Edit 2: Added UserProfile component to answer. You want to dispatch your action when the component is mounting. Also, set a ternary to show "Loading..." if state.user isn't done being fetched.

Resources