Reputation: 415
Have a loop that qualifies if an objects date key/value matches a date on a calendar. If it does I want it to append a React Link tag to the corresponding li element. The condition loop works fine, but when it appends the Link tag it is appending [object, object] since I am using createTextNode().
Is there another way to append a Link tag to an existing li without using createTextNode()?
I am done the usual google search with no luck.
for (let i = 0; i < events.length; i++) {
const link = (<Link to={`/events/${events[i].eventId}`}> .
{events[i].title}</Link>);
const eventLink = document.createTextNode(link);
if (events[i].date.slice(15) === day.toString()) {
cell.appendChild(eventLink);
}
}
Need the li element to contain the React Link tag and not a text node.
UPDATE Code with ReactDOM render and BrowserRouter but when I click the Link tag React doesn't render the route component.
for (let i = 0; i < events.length; i++) {
const link = (
<>
{day.toString()}
<Link to={`/events/${events[i].eventId}`}>{events[i].title}</Link>
</>);
const eventDate = events[i].date.split('-');
const eventYear = eventDate[0];
const eventMonth = eventDate[1];
const eventDay = eventDate[2];
if (eventDay === day.toString() &&
eventMonth === (month + 1).toString() &&
eventYear === year.toString()) {
ReactDOM.render(<BrowserRouter>{link}</BrowserRouter>, cell);
}
}
Upvotes: 1
Views: 7600
Reputation: 2232
Not sure why you need to do it this way - I'm pretty sure there are other ways to render Link
s based on an array into your DOM.
However if you insist, you should use ReactDOM
In your loop:
// create an empty div to hold our links:
const tempDiv = document.createElement('div');
// render links into the empty div
ReactDOM.render(eventLinks, tempDiv);
// append the link, since you don't want the div in cell
cell.appendChild(tempDiv.firstChild); // there is only 1 child
This is very "hacky" - I'd highly recommend looking for a real "React" way of doing this.
EDIT:
your updated code won't work. react-router
relies on an internal context to navigate, and the *Router
components provide that context - your code renders a BrowserRouter
for each link meaning each link will has its own context. Multiple routers probably won't work well in one page as they will fight control over the browser.
First of all you probably shouldn't call ReactDOM.render
in each iteration of your loop. ReactDOM.render
takes control of all the content inside your cell
- rendering it again and again meaning only the last call works.
Secondly, your BrowserRouter
should be placed at the top level of your App (e.g. in your root component).
Again, manipulating dom like that is not how you should use React. I'm curious what kind of app you are building and how it is structured?
So here's what I think you should do - since you are already using react, I imagine there is a component tree (e.g. you have a top level component that renders other components, etc.)
So at the very top of your app, you should wrap everything in the BrowserRouter.
// index.js, maybe.
// assuming App is your "top level component"
import App from './App.jsx';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>
, document.getElementById('root'))
And, now, create a EventLinks
component that renders all the links:
// EventLinks.jsx
const EventLinks = ({ events }) => (
events.map((event) => (
<li key={event.eventId}>
<Link to={`/events/${event.eventId}`}>
{event.title}
</Link>
</li>
))
);
In your component where cell
lives, render the links directly.
// Cell component
const Cell = ({ events }) => {
// filter events if you need to here, since you have that `if` logic originally
const visibleEvents = events.filter(filterFunction);
return (
<ul>
<EventLinks events={visibleEvents} />
</ul>
);
}
This is probably not exactly match your app's structure but I hope you get the idea.
so your App
renders a layout and Cell
component, and then your Cell
renders EventLinks
.
Honestly you shouldn't be using ReactDOM at all except for the only entry point of your app.
Upvotes: 3
Reputation: 566
if i am getting your questions correctly you are trying to add to a li element a link(of React link) as the text inside the li element(and if im correct as clickable link ..... anchor tag element)
cell must be the correct li element in which i assume you iterate parallel to the event, then here is a possible solution:
for (let i = 0; i < events.length; i++) {
const link = (<Link to={`/events/${events[i].eventId}`}> .
{events[i].title}</Link>);
if (events[i].date.slice(15) === day.toString()) {
let tempComponent = ReactDOM.createElement("li",{...propertiesIfNeeded},link)
ReactDOM.render(tempComponent,cell) //you could also pass here refrece to cell/li items where i wrote cell(eg.document.querySelect....)
}
}
or solution 2 creating the li as part of the link component you create in the iteration:
for (let i = 0; i < events.length; i++) {
const link = (<li><Link to={`/events/${events[i].eventId}`}> .
{events[i].title}</Link></li>);
if (events[i].date.slice(15) === day.toString()) {
ReactDOM.render(link,cell) //you could also pass here refrece to cell/li items where i wrote cell(eg.document.querySelect....)
}
}
Upvotes: 0