Passing data via props and using array.map not working - arrays

I'm currently building app and am using the firebase for data storage, and am having an issue spreading the same data to the two different components( for example: AllProjects and SelectedProject) once the user is logged in.
In the first component(AllProjects), it works and am able to map through the data array and build cards that I want to use for navigating to the second component(SelectedProject). But when I map the same data array again, to spread its content to SelectedProject component(to each individual project), the map is not working and only the data from the first project in the array is being passed to each other project.
function UserPanel(props) {
const [projects, setProjects] = useState([]);
//get data from firebase
useEffect(() => {
return db
.collection("users")
.doc(`${props.user.uid}`)
.collection("projects")
.onSnapshot(snapshot => {
const docs = [];
snapshot.forEach(doc => {
docs.push({
...doc.data()
});
});
setProjects(docs);
});
}, [props.user.uid]);
return (
<div>
<Nav user={props.user} />
<Router>
<AllProjects projects={projects} path="/" />
{projects.map(project => (
<SelectedProject
project={project}
path="projects/:projectId"
key={project.id}
/>
))}
</Router>
</div>
);
}
export default UserPanel;
First Component
function AllProjects(props) {
return (
<div>
{props.projects.map(projects=> (
<Link key={projects.id} to={`/projects/${projects.id}`}>
<ProjectCard projects={projects} />
</Link>
))}
</div>
);
}

I was not able to find the solution for spreading all data dynamically through the app(even not sure now if it's possible?) but rather making a second API call from inside the second component and using id from the router path to select the desired project.

Related

I want to redirect to another page which consist only the details of the individual object on which the user clicks. Someone help me how can i do this

I want to redirect to another page which consist only the details of the individual object on which the user clicks. Someone help me how can i do this. Thanks in advance.
function Dashboard() {
const [token, setToken] = useContext(store)
const [events, setEvents] = useState([])
useEffect(()=>{
axios.get('http://localhost:5000/api/events').then(res => {
console.log(res)
setEvents(res.data)
}).catch(err => {console.log(err)})
}, [])
if(!token){
return (
<Navigate to="/login" replace={true} />
)
}
//using map function to show data in a list. Here i want to access single item when i click on it//
return (
<>
<div className='eventelement'>
<ul>
{
events.map(event => (
<section className=''>
<li key={event._id}>
<table className='eventtable' border={1}>
<th className='eventth'><div className='eventtitle'> {event.eventname} </div></th>
<tr><div className='eventhoster'> hosted by: {event._id} </div></tr>
<tr><div className='eventdetails'> <label className='eventsh'>Event type: </label>{event.eventtype} </div></tr>
</table>
</li><br />
</section>
))
}
</ul>
</div>
<div>
</div>
</>
)
}
export default Dashboard
Give each element a click event handler that redirects the user to, say, /events/${event._id}. If you're using a recent version of react-router-dom, its useNavigate hook should give you a callback to navigate to another page.
Then add a <Route path="/events/:id" element={<EventDetailPage/>} /> to your routes.

'Maximum update depth exceeded' error when trying to use custom function passed as props in 'onClick' of button

I am trying to use a pass a function as props declared in App.js to handle a state variable in App.js in order to add items to a cart component but get this error as soon as I add the function to the onClick field of the "Add" button in my product component(at the end of post):
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
My App.js looks like this:
const App = () => {
const [cartItems, setCartItems] = useState([]);
const handleAddProduct = (product) => {
//some logic to add product to cartItems list here
}
return(
<Box className="App">
<AppRoutes handleAddProduct={handleAddProduct} cartItems={cartItems}/>
</Box>
);
}
Im passing the function and the state variable as props to my routes component so I can access it in my Products page:
const AppRoutes = ({ handleAddProduct, cartItems }) => {
return (
<Routes>
<Route exact path="/alldrip" element={<ProductsPage handleAddProduct={handleAddProduct} />} />
</Routes>
)}
And in my products page the function gets passed as props again to another component:
const ProductsPage = ({ handleAddProduct }) => {
return (
<AllProducts handleAddProduct={handleAddProduct} />
)}
And then I pass the function one last time in AllProducts to an individual Product component: ( I seperated the components this way so it is easier for me to read)
const AllProducts = ({ handleAddProduct }) => {
return (
{products.map(product => {
return (
<Product handleAddProduct={handleAddProduct} product={product} />
)
})}
)}
The products load fine but the app crashes with the error as soon as I add the function to the "Onclick" of the add to cart button:
const Product = ({ handleAddProduct, product }) => {
return (
<Heading>{product.name}</Heading>
<Text >{product.material}</Text>
<Text>{product.price} </Text>
<Button onClick={handleAddProduct(product)} >Add to Cart</Button>
)}
If I remove the function the app stays alive !
I'm not understanding why the error states setState is getting called repeatedly.
onClick={handleAddProduct(product)}
This should probably only be
onClick={() => handleAddProduct(product)}
otherwise you're calling the handleAddProduct method on render directly and not on click.
You call your handleAddProduct directly in your jsx that re-renders the component that directly call handleAddProduct and so on ...
You can try
onClick={() => handleAddProduct(product)}
A better approach is to avoid anonymous functions so in your Product component
const Product = ({ handleAddProduct, product }) => {
const onAddProduct = (product) => {
handleAddProduct(product)
}
return (
...
<Button onClick={onAddProduct}>Add to Cart</Button>
)
)}

how to pass the data from one page to another in react.js and using reach router

There is some data that I want to use on the second page am routing to that page using the reach router Link is there a way we can do so?
We can do this way when using reach-router
An object to put on location state.
Page 1(Navigated from):
const NewsFeed = () => (
<div>
<Link
to="photos/123"
state={{ fromFeed: true }}
/>
</div>
)
page 2(Navigated to):
const Photo = ({ location, photoId }) => {
if (location.state.fromFeed) {
return <FromFeedPhoto id={photoId} />
} else {
return <Photo id={photoId} />
}
}
for more details use this documentation https://reach.tech/router/api/Link[][1]

How to use a variable (a URL saved as a string) from another component?

Question: How can I use different URLs from different components in a third component as one ?
I am learning React.js and I would like to make multiple pages. This is an example project for learning purposes. There is one page where I can see the images and info of TeamA and there is another page where I can see the images and info of TeamB.
In order to avoid duplicates, I want to separate small components. I have a Card component which displays the image of team members with name and info. I want to use this one Card component for the page TeamA and also for the page TeamB.
The only difference now is the URL for the images - there is 1 URL for TeamA and one for TeamB. It should change accordingly.
I hope I could describe the problem. Please see the code examples below.
I appreciate your help. Have a nice day!
1st Component which has a unique URL for images:
const TeamA = ({id}) => {
const exampleImages = `https://url`;
return (
<div>
<Teams>
<Card teamImg={exampleImages}/>
</Teams>
</div>
);
}
2nd Component which also has a unique URL for images:
const TeamB = ({id}) => {
const exampleImagesB = `https://url`;
return (
<div>
<Teams>
<Card teamImg={exampleImagesB}/>
</Teams>
</div>
);
}
The Component that displays the information of the Team component (above). In this component, I want to use the URLs from the other components and add it to the img tag.
const Card = ({ name, email, id, teamImg }) => {
return (
<div className='tc'>
<img alt='image' src={`${teamImg}`}/>
<div>
<h2>{name}</h2>
<p>{info}</p>
</div>
</div>
);
}
You can make team a functional component of it's own:
const Team = ({id, imageUrl}) => {
return (
<div>
<Teams>
<Card teamImg={imageUrl}/>
</Teams>
</div>
);
}
Then you can pass imageUrl into your teams at a higher level without writing them out as separate components each time.
For example if you have your different urls as an array, this could be the component above team:
const AllTeams = () => {
const images = [{ id: 1, url: 'url1' }, { id: 2, url: 'url2' }];
return (
<>
{ images.map(image => <Team key={image.id} imageUrl={image.url} />) }
</>
);
}

Get data from object using FireBase

Currently i have an object from the FireBase database. Like so:
I want to render this data using React for now i have:
return (
<React.Fragment>
<StyledMain role="main">
<Layout currentUser={currentUser}>
<ListCards currentUser={currentUser} />
{data.map((item, index) => (
<Card id={Object.keys(item).toString()} key="c" type="chats">
<CardContent scrollbar={false}>
<Grid columns={`${rem(300)} 1fr`} scrollbar={false}>
{Object.keys(item).map(function(key, index) {
<Text text={item[key]['type'].toString()} />;
})}
</Grid>
</CardContent>
</Card>
))}
</Layout>
</StyledMain>
</React.Fragment>
);
Having data containing the firebase Widgets object.
My goal is to render Card where the id is erf4553o459g4 and the Text component will render lists
What is the best approach to accomplish this? Two map functions sounds a bit unnecessary.
The function to get the data from FireBase:
const getSingleRefFunction = (ref, callback) => {
const dataArray = [];
ref.once('value', snap => {
dataArray.push(snap.val());
callback(dataArray);
});
};

Resources