我无法映射自己的州,无法传递给我的孙子EmailDetails
。在尝试在EmailDetails
的呈现功能中映射urls数组之前,我可以进行控制台记录。
import React, { Component } from "react";
import IssueBox from "./issuebox.js";
import "./App.css";
class App extends Component {
constructor(props) {
super(props);
this.state = {
isLoaded: false,
emails: [],
counter: 0,
title: "Test run",
value: "",
selectedEmailId: 0,
currentSection: "inbox"
};
}
componentDidMount() {
fetch("blah")
.then(res => res.json())
.then(result => {
const emails = result.data;
console.log("resutl state: ", emails);
let id = 0;
for (const email of emails) {
email.id = id++;
}
this.setState({
isLoaded: true,
emails: emails
});
});
}
handleClickReproducibleCounter(e) {
let count = this.state.increment
? this.state.count + 1
: this.state.count - 1;
let increment = this.state.increment;
if (count === 0) {
increment = true;
} else if (count >= 2) {
increment = false;
}
this.setState({
count,
increment
});
}
render() {
return (
<div className="App">
<div>
emails={this.state.emails}
selectedEmailId={this.state.selectedEmailId}
onEmailSelected={id => {
this.openEmail(id);
}}
handleClickReproducibleCounter={this.handleClickReproducibleCounter}
</div>
</div>
);
}
}
//数据如下:
[
{
groupID: "65da6a",
urls: [
{
id: 85,
searchedurl: "https://www.yahoo.com",
errorurl: "https://www.yahoo.com/error505",
count: 1,
reproducible: false,
reproducible_counter: 0
},
{
id: 84,
searchedurl: "https://www.gmail.com",
errorurl: "https://www.gmail.com/error404",
count: 1,
reproducible: false,
reproducible_counter: 0
}
]
},
{
groupID: "d4127e",
urls: [
{
id: 3,
searchedurl: "agwscc",
errorurl: "xyqa",
count: 1,
reproducible: false,
reproducible_counter: 0,
resolved: null
}
]
}
];
// issuebox.js
import React, { Component } from "react";
import "./App.css";
import EmailDetails from "./emailDetails";
class IssueBox extends Component {
constructor(args) {
super(args);
}
render() {
const currentEmail = this.props.emails.find(
x => x.id === this.props.selectedEmailId
);
console.log("emailDetail view: ", currentEmail); // email obj is present
return (
<div className="wrapper">
<div className="inbox-container">
<EmailList
emails={this.props.emails}
onEmailSelected={this.props.onEmailSelected}
selectedEmailId={this.props.selectedEmailId}
/>
<EmailDetails
email={currentEmail}
onReproducibleCounter={this.props.handleClickReproducibleCounter}
onValidateSumbit={this.props.handleClickValidateSumbission}
handleTextInputChange={this.props.handleTextInputChange}
/>
</div>
</div>
);
}
}
export default IssueBox;
// EmailDetails
import React, { Component } from "react";
import "./App.css";
class EmailDetails extends Component {
constructor(args) {
super(args);
this.state = {
counter: "",
email: []
};
}
componentDidUpdate(prevProps) {
if (this.props.email !== prevProps.email) {
this.setState({ email: this.props.email });
}
}
render() {
const currentEmail = this.state.email;
console.log(currentEmail, this.state.email.urls); // able to console obj
const test = this.state.email.urls.map(obj => {
//error occurs here
console.log(obj);
});
return (
<div className="email-content">
<div className="email-content__header">
<h3 className="email-content__subject">Issue</h3>
<div className="email-content__from">Group:</div>
</div>
<div className="email-content__message">
<table role="table">
<thead role="rowgroup">
<tr role="row">
<th role="columnheader">Searched URL</th>
<th role="columnheader">Error URL</th>
<th role="columnheader">NR</th>
<th role="columnheader">Task</th>
</tr>
</thead>
<tbody role="rowgroup" className="group-row" />
</table>
</div>
</div>
);
}
}
export default EmailDetails;
以此为起点:codepen
答案 0 :(得分:1)
我本来要写评论,但要更长一些,所以我决定提供一个答案。
遵循您的代码有点困难,但是我看到了一些问题,还有一些我不理解的事情。
首先,您没有将handleClickReproducibleCounter
绑定到App
中。因此,您不能将this
用于回调函数。将其绑定到构造函数中,或者使用箭头函数代替。
handleClickReproducibleCounter = (e) => {
...
}
第二,您正在EmailDetails
组件中使用此功能,例如:
<button onClick={this.props.onReproducibleCounter(obj.id)}>
您为什么要使用this.props
?不需要this
,而且您已经从道具中破坏了onReproducibleCounter
。另外,您这里没有在onClick
处理函数中使用回调,而是立即使用参数调用该函数,而这并不是您真正想要的。
所以,应该像这样:
<button onClick={() => onReproducibleCounter(obj.id)}>
但是,使用箭头功能或绑定JSX props中的功能并不是很好,因为它们在每个渲染器中都会重新创建。但是,根据您的情况,更改此逻辑有些棘手。您正在将道具传递给子组件并在其中映射一些东西。一种简单的方法是,在父级中进行映射,然后将单个项目传递给子级组件。
现在,我不了解的事情。您正在将一些obj.id
传递给回调函数,但正在等待e
吗?看来您在函数中的任何地方都没有使用此参数。
我不了解的第二件事是在您的地图中,您使用的第二个参数为onReproducibleCounter
email.urls.map((obj, onReproducibleCounter) => {
此处的第二个参数是index
。
评论后更新
您正在使用异步作业在父级中获取此数据。当您尝试在this.state.email.urls
上进行映射时,那时没有this.state.email.urls
,那么您会收到错误消息。
只需使用条件渲染或日志记录即可。
(this.state.email.urls || [] ).map(obj => {
//error occurs here
console.log(obj);
});
因此,如果没有email.urls
,那么我们的地图将使用一个空数组,这对我们来说是可以的。提取完成后,该组件将重新呈现,它将映射实际数据。
但是,不要将道具变成孩子的状态。在此处使用email
道具。如果您需要对其进行处理,请在您的子组件中进行处理。
这是一个非常简单而愚蠢的示例:
const Child = (props) => {
const doSomething = () => {
const newNumber = props.number * 20;
props.handleNumber( newNumber );
}
return (
<div>
<button onClick={doSomething}>Click me, so do something in the Child and change this number.</button>
</div>
);
}
class App extends React.Component {
state = {
number: 10,
}
handleNumber = number => this.setState({number});
render() {
return <div>
<p>Number is: {this.state.number}</p>
<Child number={this.state.number} handleNumber={this.handleNumber} />
</div>;
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
答案 1 :(得分:0)
希望我能理解您的要求,当您将此类回调传递给孩子时,您需要确保this
关键字指向正确的内容。
最简单的方法是使用fat arrow函数,
handleClickReproducibleCounter(e) {
成为
handleClickReproducibleCounter = e => {
您还可以在constructor
函数中添加一行,以完成此操作
this.handleClickReproducibleCounter = this.handleClickReproducibleCounter.bind(this)
这样做是为了确保在调用handleClickReproducibleCounter
时,this.state
始终指代父组件的状态(或其绑定到的任何组件)。
关于您的问题:
这是否意味着我需要跟踪孙子中的单独状态?
正确,您不需要。只要回调函数已正确绑定到父组件状态,便可以将回调传递至任意范围,并且您可以在应用程序中的任意位置更改该状态。