在反应中显示每个动态 div 的组件
Show component for each dynamic div in react
我正在尝试为动态生成的 div 渲染组件 HomeScreen.js。我能够让它有点工作,但我无法将组件与动态生成的 div 分开,而且我只是试图为 [=29] 渲染 HomeScreen.js =] 被点击,但我目前拥有的功能为所有 divs 打开 HomeScreen.js。
(这是一个联系人应用程序,动态生成的 div 是联系人。我只是想显示每个被点击的联系人的联系信息)
我附上了当前功能和我正在尝试获得的功能的屏幕截图
我可以使用一些见识。
import store from '../libs/store.js';
var jsforce = require('jsforce');
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
showModal: false,
showChat: false
}
}
handleSearch(e) {
this.setState({
username: e.target.value
})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onClick(e) {
e.preventDefault();
this.setState({
showChat: !this.state.showChat
})
}
onLinkClicked() {
var conn = new jsforce.Connection({
serverUrl: 'https://cs63.salesforce.com',
accessToken: sessionStorage.getItem('token')
})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone, Account.Name'
).sort('-CreatedDate Name').
limit(5).skip(10).execute(function(err, records) {
if (err) {
return console.error(err);
}
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name);
console.log("Phone: " + record.Phone);
console.log("Account Name: " + record.Account.Name);
}
this.setState({
records: records
})
this.setState({
showChat: !this.state.showChat
})
}.bind(this))
}
render() {
return (
<div className='menubox' id='menubox'>
<div className="boxbox">
<input className="search" type="text" placeholder="Contact Last Name" onChange={this.handleChange.bind(this)} value={this.state.username} />
<input className="submit" type="submit" onClick={this.onLinkClicked.bind(this)} value="GO" /></div>
<div>
<div>
{this.state.records.map(record => (
<div className="info-block block-info clearfix">
<div className="square-box pull-left">
<span className="glyphicon glyphicon-user glyphicon-lg"></span>
</div>
<h5>{record.Name}</h5>
<h4>{record.Phone}</h4>
<p>{record.Account.Name}</p>
**//Trying to render home.js when Chat Bubble is clicked.**
<a onClick={this.onClick.bind(this)}>
<img src="./img/speechbubble.png" className="textIcon" />
{this.state.showChat && < HomeScreen / >}
</a>
</div>
))}
</div>
</div>
</div>
)
}
}
export default menuScreen;
原因是,您使用单个 state
变量来控制所有 dynamic div
,您需要使用一个 array
,每个元素的每个值,所以而不是 showChat = false
,在 state
变量中使用 showChat = []
。要在 onClick
函数中更改 array
的值,您需要在 onClick
函数中传递元素的索引,并使用该索引来更改特定值。
对于其他更改,请检查代码和注释,它应该可以工作。
使用这个:
import store from '../libs/store.js';
var jsforce = require('jsforce');
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
showModal: false,
showChat: [] //initially blank array
}
}
handleSearch(e) {
this.setState({
username: e.target.value
})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onClick(i, e) { // pass the index on item clicked
e.preventDefault();
let showChat = this.state.showChat.slice();
showChat[i] = !showChat[i]; //use that index to change the specific value
this.setState({ showChat })
}
onLinkClicked() {
var conn = new jsforce.Connection({
serverUrl: 'https://cs63.salesforce.com',
accessToken: sessionStorage.getItem('token')
})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone, Account.Name'
).sort('-CreatedDate Name').
limit(5).skip(10).execute((err, records) => { //use arrow function
if (err) {
return console.error(err);
}
// this loop is not required
/*
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name);
console.log("Phone: " + record.Phone);
console.log("Account Name: " + record.Account.Name);
}
*/
console.log('recoreds values', records);
this.setState({
records: records,
})
})
}
render() {
return (
<div className='menubox' id='menubox'>
<div className="boxbox">
<input className="search" type="text" placeholder="Contact Last Name" onChange={this.handleChange.bind(this)} value={this.state.username} />
<input className="submit" type="submit" onClick={this.onLinkClicked.bind(this)} value="GO" /></div>
<div>
<div>
/*use the index also in map*/
{this.state.records.map((record, i) => (
<div className="info-block block-info clearfix">
<div className="square-box pull-left">
<span className="glyphicon glyphicon-user glyphicon-lg"></span>
</div>
<h5>{record.Name}</h5>
<h4>{record.Phone}</h4>
<p>{record.Account.Name}</p>
<a onClick={this.onClick.bind(this, i)}>
<img src="./img/speechbubble.png" className="textIcon" />
{this.state.showChat[i] && < HomeScreen / >}
{/*use this.state.showChat[i] specific value*/}
</a>
</div>
))}
</div>
</div>
</div>
)
}
}
export default menuScreen;
建议:不要在render中绑定方法,而是在构造函数中定义绑定,像这样:
this.handleChange = this.handleChange.bind(this);
直接使用:
onChange={this.handleChange}
我同意 Mayank 关于对 showChat
使用数组的回答,但是基于这个想法,有什么理由不能让每个联系人都成为一个单独的组件?就个人而言,我会渲染一个子组件数组,例如 Contact 组件或其他组件,并从外部 menuScreen 组件中的状态将 props 传递给它们中的每一个。
class Contact extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<div className="info-block block-info clearfix">
<div className="square-box pull-left">
<span className="glyphicon glyphicon-user glyphicon-lg"></span>
</div>
<h5>{record.Name}</h5>
<h4>{record.Phone}</h4>
<p>{record.Account.Name}</p>
<a onClick={this.props.onClick}>
<img src="./img/speechbubble.png" className="textIcon" />
{this.props.showChat && < HomeScreen / >}
</a>
</div>
)
}
}
然后您可以像这样在 menuScreen 组件中使用它:
import store from '../libs/store.js';
var jsforce = require('jsforce');
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
showModal: false,
showChat: []
}
}
handleSearch(e) {
this.setState({
username: e.target.value
})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onClick(i, e) {
e.preventDefault();
let showChat = this.state.showChat.slice();
showChat[i] = !showChat[i];
this.setState({ showChat })
}
onLinkClicked() {
var conn = new jsforce.Connection({
serverUrl: 'https://cs63.salesforce.com',
accessToken: sessionStorage.getItem('token')
})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone, Account.Name'
).sort('-CreatedDate Name').
limit(5).skip(10).execute((err, records) => {
if (err) {
return console.error(err);
}
// this loop is not required
/*
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name);
console.log("Phone: " + record.Phone);
console.log("Account Name: " + record.Account.Name);
}
*/
console.log('recoreds values', records);
this.setState({
records: records,
})
})
}
render() {
return (
<div className='menubox' id='menubox'>
<div className="boxbox">
<input className="search" type="text" placeholder="Contact Last Name" onChange={this.handleChange.bind(this)} value={this.state.username} />
<input className="submit" type="submit" onClick={this.onLinkClicked.bind(this)} value="GO" /></div>
<div>
<div>
{this.state.records.map((record, i) => (
<Contact onClick={onClick.bind(this, i)} showChat={this.state.showChat[i]} />
))}
</div>
</div>
</div>
)
}
}
export default menuScreen;
可能更多的是一种意见,而不仅仅是一个答案,但通常最好将组件中的表示与状态分开。这样它也更具可扩展性,因为子 Contact 组件仍然可以在 运行 menuScreen
组件的 onClick
函数之前执行其他操作,使其几乎像一个装饰器。
我正在尝试为动态生成的 div 渲染组件 HomeScreen.js。我能够让它有点工作,但我无法将组件与动态生成的 div 分开,而且我只是试图为 [=29] 渲染 HomeScreen.js =] 被点击,但我目前拥有的功能为所有 divs 打开 HomeScreen.js。
(这是一个联系人应用程序,动态生成的 div 是联系人。我只是想显示每个被点击的联系人的联系信息)
我附上了当前功能和我正在尝试获得的功能的屏幕截图
我可以使用一些见识。
import store from '../libs/store.js';
var jsforce = require('jsforce');
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
showModal: false,
showChat: false
}
}
handleSearch(e) {
this.setState({
username: e.target.value
})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onClick(e) {
e.preventDefault();
this.setState({
showChat: !this.state.showChat
})
}
onLinkClicked() {
var conn = new jsforce.Connection({
serverUrl: 'https://cs63.salesforce.com',
accessToken: sessionStorage.getItem('token')
})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone, Account.Name'
).sort('-CreatedDate Name').
limit(5).skip(10).execute(function(err, records) {
if (err) {
return console.error(err);
}
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name);
console.log("Phone: " + record.Phone);
console.log("Account Name: " + record.Account.Name);
}
this.setState({
records: records
})
this.setState({
showChat: !this.state.showChat
})
}.bind(this))
}
render() {
return (
<div className='menubox' id='menubox'>
<div className="boxbox">
<input className="search" type="text" placeholder="Contact Last Name" onChange={this.handleChange.bind(this)} value={this.state.username} />
<input className="submit" type="submit" onClick={this.onLinkClicked.bind(this)} value="GO" /></div>
<div>
<div>
{this.state.records.map(record => (
<div className="info-block block-info clearfix">
<div className="square-box pull-left">
<span className="glyphicon glyphicon-user glyphicon-lg"></span>
</div>
<h5>{record.Name}</h5>
<h4>{record.Phone}</h4>
<p>{record.Account.Name}</p>
**//Trying to render home.js when Chat Bubble is clicked.**
<a onClick={this.onClick.bind(this)}>
<img src="./img/speechbubble.png" className="textIcon" />
{this.state.showChat && < HomeScreen / >}
</a>
</div>
))}
</div>
</div>
</div>
)
}
}
export default menuScreen;
原因是,您使用单个 state
变量来控制所有 dynamic div
,您需要使用一个 array
,每个元素的每个值,所以而不是 showChat = false
,在 state
变量中使用 showChat = []
。要在 onClick
函数中更改 array
的值,您需要在 onClick
函数中传递元素的索引,并使用该索引来更改特定值。
对于其他更改,请检查代码和注释,它应该可以工作。
使用这个:
import store from '../libs/store.js';
var jsforce = require('jsforce');
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
showModal: false,
showChat: [] //initially blank array
}
}
handleSearch(e) {
this.setState({
username: e.target.value
})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onClick(i, e) { // pass the index on item clicked
e.preventDefault();
let showChat = this.state.showChat.slice();
showChat[i] = !showChat[i]; //use that index to change the specific value
this.setState({ showChat })
}
onLinkClicked() {
var conn = new jsforce.Connection({
serverUrl: 'https://cs63.salesforce.com',
accessToken: sessionStorage.getItem('token')
})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone, Account.Name'
).sort('-CreatedDate Name').
limit(5).skip(10).execute((err, records) => { //use arrow function
if (err) {
return console.error(err);
}
// this loop is not required
/*
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name);
console.log("Phone: " + record.Phone);
console.log("Account Name: " + record.Account.Name);
}
*/
console.log('recoreds values', records);
this.setState({
records: records,
})
})
}
render() {
return (
<div className='menubox' id='menubox'>
<div className="boxbox">
<input className="search" type="text" placeholder="Contact Last Name" onChange={this.handleChange.bind(this)} value={this.state.username} />
<input className="submit" type="submit" onClick={this.onLinkClicked.bind(this)} value="GO" /></div>
<div>
<div>
/*use the index also in map*/
{this.state.records.map((record, i) => (
<div className="info-block block-info clearfix">
<div className="square-box pull-left">
<span className="glyphicon glyphicon-user glyphicon-lg"></span>
</div>
<h5>{record.Name}</h5>
<h4>{record.Phone}</h4>
<p>{record.Account.Name}</p>
<a onClick={this.onClick.bind(this, i)}>
<img src="./img/speechbubble.png" className="textIcon" />
{this.state.showChat[i] && < HomeScreen / >}
{/*use this.state.showChat[i] specific value*/}
</a>
</div>
))}
</div>
</div>
</div>
)
}
}
export default menuScreen;
建议:不要在render中绑定方法,而是在构造函数中定义绑定,像这样:
this.handleChange = this.handleChange.bind(this);
直接使用:
onChange={this.handleChange}
我同意 Mayank 关于对 showChat
使用数组的回答,但是基于这个想法,有什么理由不能让每个联系人都成为一个单独的组件?就个人而言,我会渲染一个子组件数组,例如 Contact 组件或其他组件,并从外部 menuScreen 组件中的状态将 props 传递给它们中的每一个。
class Contact extends React.Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
return (
<div className="info-block block-info clearfix">
<div className="square-box pull-left">
<span className="glyphicon glyphicon-user glyphicon-lg"></span>
</div>
<h5>{record.Name}</h5>
<h4>{record.Phone}</h4>
<p>{record.Account.Name}</p>
<a onClick={this.props.onClick}>
<img src="./img/speechbubble.png" className="textIcon" />
{this.props.showChat && < HomeScreen / >}
</a>
</div>
)
}
}
然后您可以像这样在 menuScreen 组件中使用它:
import store from '../libs/store.js';
var jsforce = require('jsforce');
class menuScreen extends React.Component {
constructor(props) {
super(props)
const data = store.getState();
this.state = {
username: '',
messages: data.messages,
records: [],
showModal: false,
showChat: []
}
}
handleSearch(e) {
this.setState({
username: e.target.value
})
}
handleChange(evt) {
this.setState({
username: evt.target.value.substr(0, 100)
});
}
onClick(i, e) {
e.preventDefault();
let showChat = this.state.showChat.slice();
showChat[i] = !showChat[i];
this.setState({ showChat })
}
onLinkClicked() {
var conn = new jsforce.Connection({
serverUrl: 'https://cs63.salesforce.com',
accessToken: sessionStorage.getItem('token')
})
var parent = this.state.username
//console.log(this.state.username)
conn.sobject("Contact").find({
LastName: {
$like: parent
}
}, 'Id, Name, Phone, Account.Name'
).sort('-CreatedDate Name').
limit(5).skip(10).execute((err, records) => {
if (err) {
return console.error(err);
}
// this loop is not required
/*
for (var i = 0; i < records.length; i++) {
var record = (records[i]);
console.log("Name: " + record.Name);
console.log("Phone: " + record.Phone);
console.log("Account Name: " + record.Account.Name);
}
*/
console.log('recoreds values', records);
this.setState({
records: records,
})
})
}
render() {
return (
<div className='menubox' id='menubox'>
<div className="boxbox">
<input className="search" type="text" placeholder="Contact Last Name" onChange={this.handleChange.bind(this)} value={this.state.username} />
<input className="submit" type="submit" onClick={this.onLinkClicked.bind(this)} value="GO" /></div>
<div>
<div>
{this.state.records.map((record, i) => (
<Contact onClick={onClick.bind(this, i)} showChat={this.state.showChat[i]} />
))}
</div>
</div>
</div>
)
}
}
export default menuScreen;
可能更多的是一种意见,而不仅仅是一个答案,但通常最好将组件中的表示与状态分开。这样它也更具可扩展性,因为子 Contact 组件仍然可以在 运行 menuScreen
组件的 onClick
函数之前执行其他操作,使其几乎像一个装饰器。