admin管理员组文章数量:1430551
I am learning react-router and I need help in the following problem:
I am iterating through an array of strings called nameArr. I would like to create a list of clickable links of the strings using react-router so that each link will navigate though a route defined in route.js.
The array nameArr is populated from the response created by a server.
The following code focuses on creating a list and applying it to the JSX.
var React = require('react');
var Router = require('react-router');
var createReactClass = require('create-react-class');
var Link = Router.Link;
var request = require('superagent'); //Superagent is an AJAX API used in Node.
var classComp = createReactClass({
request.post('/getdata')
.end(function (err, res) {
if (err || !res.ok) {
console.log('Oh no! err');
} else {
var response = JSON.parse(res.text);
var i;
var pathArr = [];
var nameArr = [];
for (i = 0; i < response.length; i++) {
pathArr[i] = response[i].videourl;
nameArr[i] = response[i].name;
}
var displayItem = "<div className=\"container\">";
for (var m in nameArr) {
displayItem += "<div class='text-center'><Link to='play'><h3>" + nameArr[m].toString() + "</h3></Link></div>";
}
displayItem += "</div>";
document.getElementById("vdlist").innerHTML = displayItem;
}
render: function () {
return (
<div className="container center-block vlsection1">
{this.display()}
<h1 className="text-center">Videos</h1>
<div id="vdlist">
</div>
</div>
);
}
});
When I run the application, the List is generated but the links are not showing. That is no action happens when I click the links. Please suggest how I can approach this problem in a better way.
Thanks a lot!
I am learning react-router and I need help in the following problem:
I am iterating through an array of strings called nameArr. I would like to create a list of clickable links of the strings using react-router so that each link will navigate though a route defined in route.js.
The array nameArr is populated from the response created by a server.
The following code focuses on creating a list and applying it to the JSX.
var React = require('react');
var Router = require('react-router');
var createReactClass = require('create-react-class');
var Link = Router.Link;
var request = require('superagent'); //Superagent is an AJAX API used in Node.
var classComp = createReactClass({
request.post('/getdata')
.end(function (err, res) {
if (err || !res.ok) {
console.log('Oh no! err');
} else {
var response = JSON.parse(res.text);
var i;
var pathArr = [];
var nameArr = [];
for (i = 0; i < response.length; i++) {
pathArr[i] = response[i].videourl;
nameArr[i] = response[i].name;
}
var displayItem = "<div className=\"container\">";
for (var m in nameArr) {
displayItem += "<div class='text-center'><Link to='play'><h3>" + nameArr[m].toString() + "</h3></Link></div>";
}
displayItem += "</div>";
document.getElementById("vdlist").innerHTML = displayItem;
}
render: function () {
return (
<div className="container center-block vlsection1">
{this.display()}
<h1 className="text-center">Videos</h1>
<div id="vdlist">
</div>
</div>
);
}
});
When I run the application, the List is generated but the links are not showing. That is no action happens when I click the links. Please suggest how I can approach this problem in a better way.
Thanks a lot!
Share Improve this question edited Mar 20, 2018 at 5:17 MVG asked Mar 19, 2018 at 11:29 MVGMVG 3141 gold badge4 silver badges18 bronze badges 6-
As an aside I'd remend using single quotes in your JS and double quotes for your HTML - that way you won't need to escape your code:
'<div className="container">'
. – Andy Commented Mar 19, 2018 at 11:32 -
did you
import {Link} from "react-router-dom"
? do you get the value of ` nameArr[m].toString()` , can you please update your question with more information ? – Abslen Char Commented Mar 19, 2018 at 11:34 -
You're attempting to achieve a side-effect in your render function, the side effect being "Find a #id of vdlist and hack its innerHTML". In my mind that would be better done in
ponentDidMount
and/orponentDidUpdate
. I'm surprised you're not getting a JS console error when you run this. I would think the #vdlist element doesn't exist when.display()
runs. React has in-built support for generating HTML, why don't you use it? In that case you can return JSX from.display()
and React will handle updating your HTML whennameArr
is updated. – Rajit Commented Mar 19, 2018 at 11:38 - Hi Rajit, Thanks for the info. However I would like to tell that there has been no console error and also the list is being populated. That means that #vdlist is identified. The issue is that the elements of the list are text but not links as I want them to be. Anyways, I shall try as you suggest and update. – MVG Commented Mar 19, 2018 at 11:49
- Hi Abdeslem, I have updated the question. Please do notify if more clarity is needed. – MVG Commented Mar 19, 2018 at 11:50
3 Answers
Reset to default 2As already mentioned in the ment by Rajit, you try to access a dom element in the render function. This is never a good idea and shouldn't ever be done.
It is also not the correct way in React to access the dom directly since you will loose some powerful tools of react, like the virtual dom.
A better way would be to use JSX. And by JSX, I mean real JSX. There is a difference between a string that "looks" like JSX and actual JSX. What you try to do is to create a string with JSX inside. Then you add this string into the dom - using the innerHTML property. However, your JSX won't really be handled as JSX. It will just handle it like HTML - and there is no <Link /> element in HTML. That's why you can't see the items.
Instead do it like this:
import React, { Component } from 'react';
import { Link } from 'react-router-dom'; // You need to use react-router-dom here
class VideoList extends Component {
constructor(props) {
super(props);
this.nameArr = ['name1', 'name2'];
}
getVideos() {
// This creates a JSX element for every name in the list.
return this.nameArr.map(name => <div className="text-center"><Link to="play"><h3>{name}</h3></Link></div>);
}
render() {
return (
<div className="container center-block vlsection1">
<h1 className="text-center">Videos</h1>
{this.getVideos()}
</div>
);
}
}
A more idiomatic way of doing this:
render: function () {
return (
<div className="container center-block vlsection1">
<h1 className="text-center">Videos</h1>
<div id="vdlist">
{nameArr.map(name => (
<div key={name} className="container">
<div class="text-center"><Link to="play"><h3>{name.toString()}</h3></Link></div>
</div>
))}
</div>
</div>
);
}
FYI you can't use JSX-only elements (like <Link/>
) in .innerHTML
.
EDIT[Explanation]:
React is built to make it easier to manage dynamic web pages, and essentially replaces the need to use things like .innerHTML
. If you're using React and find yourself trying to use .innerHTML
it is most likely you're going in the wrong direction.
Any capitalised element you can be sure is not an original HTML element but is instead a React ponent. If that's the case then the appropriate place to use it is within a JSX block (or possibly directly as a React ponent, if you prefer). So <Link/>
, <Router/>
and any other tag beginning with a capitable letter.
What I've done is added a block of JavaScript to your .render
JSX that maps over the nameArr
array and generates the code you were trying to generate from your .display
method. As you can see, you can insert arbitrary JavaScript into JSX by putting it between {}
braces.
EDIT[to answer updated question]:
Your nameArr
variable is only available in the .end()
function for the request you're making so of course you don't have access to it in the render
function. React provides a feature exactly for this case! React state! You can read up more about State and Lifecycle.
In this case all you need to do is initialise some state for your class and then update it when you receive new data. The way you initialise state using the pre-ES6 style you're using is by adding a getInitialState
key to your createReactClass
argument:
getInitialState: function() {
return { nameArr: [] };
},
In this case I've initialised nameArr
to be an empty array. Then in your render
function you can refer to this.state.nameArr
:
render: function () {
return (
<div className="container center-block vlsection1">
<h1 className="text-center">Videos</h1>
<div id="vdlist">
{this.state.nameArr.map(name => (
<div key={name} className="container">
<div class="text-center"><Link to="play"><h3>{name.toString()}</h3></Link></div>
</div>
))}
</div>
</div>
);
}
Once you do this if we don't update it anywhere, it will always be empty. To update it, we call this.setState({ ... })
. This is how it would work with your request call:
request.post('/getdata')
.end(function (err, res) {
var response;
var i;
var nameArr = [];
if (err || !res.ok) {
console.log('Oh no! err');
// NOTE: You should probably set an error in state here:
// this.setState({ error: '...' });
} else {
var response = JSON.parse(res.text);
// NOTE: .map is an easier way to extract the name here
nameArr = response.map(function (p) { return p.name });
// This is where you update your React state.
this.setState({ nameArr: nameArr });
}
});
Once you've done this, your React class should update quickly and efficiently. This is the power of React and hopefully you can see that this is much easier than attempting to build HTML all over again. Instead you can just rely on one render
method.
You could try an Anchor and then Link ponent as:
<Anchor>
<Link to={`crew/${crew._id}`}> {`${crew.name}`}</Link>
</Anchor>
本文标签: javascriptCreating a dynamic list of Links in reactrouterStack Overflow
版权声明:本文标题:javascript - Creating a dynamic list of Links in react-router - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1745559555a2663389.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论