React with react-router-dom 4 -- 无法读取未定义的 属性 'params'
React with react-router-dom 4 -- Cannot read property 'params' of undefined
我一直在努力学习 React,看看它是否适合我组织的需求,所以不用说我是新手。我有一个示例应用程序,我一直在研究它是如何工作的。我在这里浏览了几个答案,但没有找到解决我问题的答案。
我 运行 遇到以下组件的 "componentDidMount()" at "const { match: { params } } = this.props;" 方法中出现 "Uncaught (in promise) TypeError: Cannot read property 'params' of undefined" 的问题。我有一个非常相似的组件,它使用相同的方法从 url 获取一个 id,并且工作正常。我对为什么一个在工作而另一个不工作感到困惑。我可能只是在某个地方犯了一个菜鸟错误(可能不止一个),任何 hints/answers 都表示赞赏。
路由:
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Route path='/' component={BaseView} />
<Route path='/test' component={NameForm} />
<Route path='/home' component={Home} />
<Route path='/quizzes' component={ViewQuizzes} />
<Route path='/comment/:rank' component={GetCommentsId} /*The one that works*//>
<Route path='/comment/edit/:testid' component={GetCommentEdit} /*The one I'm having trouble with*//>
<Route path='/comments' component={GetCommentsAll} />
</div>
</BrowserRouter>
);
}
}
工作组件:
class GetCommentsId extends Component{
constructor (props) {
super(props)
this.state = {
Comments: [],
output: "",
wasClicked: false,
currentComment: " ",
}
this.handleCommentChange = this.handleCommentChange.bind(this);
}
componentDidMount(){
const { match: { params } } = this.props;
const url = 'http://localhost:51295/api/Values/' + params.rank;
axios.get(url).then(res => {
const comments = res.data;
this.setState({ comments });
this.output = (
<div>
<ul>
{ this.state.comments.map
(
comment =>
(<Comment
QuizId = {comment.Rank}
FirstName = {comment.FirstName}
Comments = {comment.Comments}
TestId = {comment.TestimonialId}
/>)
)}
</ul>
</div>
);
//console.log("From did mount: " + this.currentComment);
this.forceUpdate();
});
}
componentDidUpdate(){}
handleCommentChange(event){
//console.log("handle Comment Change activated");
}
handleClick(comment){
this.wasClicked = true;
this.currentComment = comment.Comments;
console.log(comment.Comments);
this.forceUpdate();
}
render () {
if(this.output != null){
if(!this.wasClicked){
return (this.output);
}
else{
console.log("this is the current comment: " + this.currentComment);
return(
<div>
{this.output}
<NameForm value={this.currentComment}/>
</div>
);
}
}
return ("loading");
}
}
不起作用的那个:
class GetCommentEdit extends Component {
constructor (props) {
super(props)
this.state = {
Comments: [],
output: "",
match: props.match
}
}
componentDidMount(){
const { match: { params } } = this.props;
const url = 'http://localhost:51295/api/Values/' + params.testid;
axios.get(url).then(res => {
const comments = res.data;
this.setState({ comments });
this.output = (
<div>
<ul>
{ this.state.comments.map
(comment =>
(<EditComment
QuizId = {comment.Rank}
FirstName = {comment.FirstName}
Comments = {comment.Comments}
TestId = {comment.TestimonialId}
/>)
)}
</ul>
</div>
);
//console.log("From did mount: " + this.currentComment);
this.forceUpdate();
});
}
render(){
return(
<div>
{this.output}
</div>
);
}
}
我为您创建了一个小应用程序来演示如何实现工作 react router v4
。
在每条路线上都有一个道具转储,你可以看到那里的参数是可见的。
在你的代码中,我不明白你为什么不使用 react-router v4
中的 Switch
,而且你的路线没有 exact
flag/prop。这样你就不会一个接一个地渲染你的组件视图了。
Link 到沙箱:https://codesandbox.io/s/5y9310y0zn
请注意,建议将withRouter
包裹在App组件周围,App组件不应包含<BrowserRouter>
。
审查您的代码
请注意,更新状态会触发组件的新渲染。
不要使用此处不需要的 this.forceUpdate()
,而是使用通过解析 Promise/axios 请求获得的值更新您的状态。
// Bad implementation of componentDidMount
// Just remove it
this.output = (
<div>
<ul>
{this.state.comments.map
(
comment =>
(<Comment
QuizId={comment.Rank}
FirstName={comment.FirstName}
Comments={comment.Comments}
TestId={comment.TestimonialId}
/>)
)}
</ul>
</div>
);
//console.log("From did mount: " + this.currentComment);
this.forceUpdate();
在 render 方法或任何其他辅助方法中移动循环函数,这里是使用辅助方法的代码。
renderComments() {
const { comments } = this.state;
// Just check if we have any comments
// Return message or just return null
if (!comments.length) return <div>No comments</div>;
// Move li inside loop
return (
<ul>
{comments.map(comment => (
<li key={comment.id}>
<Comment yourProps={'yourProps'} />
</li>
))}
</ul>
)
};
在您的初始状态中添加类似 isLoading
的内容。每次完成抓取或开始抓取时切换 isLoading 状态。
this.setState({ isLoading: true }); // or false
// Initial state or implement in constructor
state = { isLoading: true };
Render 方法将在我们每次加载内容时向我们显示加载,renderComments()
将 return 我们评论。我们得到干净且可读的代码。
render() {
if (isLoading) {
return <div>Loading...</div>
}
return (
<div>
{this.renderComments()}
</div>
);
}
我一直在努力学习 React,看看它是否适合我组织的需求,所以不用说我是新手。我有一个示例应用程序,我一直在研究它是如何工作的。我在这里浏览了几个答案,但没有找到解决我问题的答案。
我 运行 遇到以下组件的 "componentDidMount()" at "const { match: { params } } = this.props;" 方法中出现 "Uncaught (in promise) TypeError: Cannot read property 'params' of undefined" 的问题。我有一个非常相似的组件,它使用相同的方法从 url 获取一个 id,并且工作正常。我对为什么一个在工作而另一个不工作感到困惑。我可能只是在某个地方犯了一个菜鸟错误(可能不止一个),任何 hints/answers 都表示赞赏。
路由:
class App extends Component {
render() {
return (
<BrowserRouter>
<div>
<Route path='/' component={BaseView} />
<Route path='/test' component={NameForm} />
<Route path='/home' component={Home} />
<Route path='/quizzes' component={ViewQuizzes} />
<Route path='/comment/:rank' component={GetCommentsId} /*The one that works*//>
<Route path='/comment/edit/:testid' component={GetCommentEdit} /*The one I'm having trouble with*//>
<Route path='/comments' component={GetCommentsAll} />
</div>
</BrowserRouter>
);
}
}
工作组件:
class GetCommentsId extends Component{
constructor (props) {
super(props)
this.state = {
Comments: [],
output: "",
wasClicked: false,
currentComment: " ",
}
this.handleCommentChange = this.handleCommentChange.bind(this);
}
componentDidMount(){
const { match: { params } } = this.props;
const url = 'http://localhost:51295/api/Values/' + params.rank;
axios.get(url).then(res => {
const comments = res.data;
this.setState({ comments });
this.output = (
<div>
<ul>
{ this.state.comments.map
(
comment =>
(<Comment
QuizId = {comment.Rank}
FirstName = {comment.FirstName}
Comments = {comment.Comments}
TestId = {comment.TestimonialId}
/>)
)}
</ul>
</div>
);
//console.log("From did mount: " + this.currentComment);
this.forceUpdate();
});
}
componentDidUpdate(){}
handleCommentChange(event){
//console.log("handle Comment Change activated");
}
handleClick(comment){
this.wasClicked = true;
this.currentComment = comment.Comments;
console.log(comment.Comments);
this.forceUpdate();
}
render () {
if(this.output != null){
if(!this.wasClicked){
return (this.output);
}
else{
console.log("this is the current comment: " + this.currentComment);
return(
<div>
{this.output}
<NameForm value={this.currentComment}/>
</div>
);
}
}
return ("loading");
}
}
不起作用的那个:
class GetCommentEdit extends Component {
constructor (props) {
super(props)
this.state = {
Comments: [],
output: "",
match: props.match
}
}
componentDidMount(){
const { match: { params } } = this.props;
const url = 'http://localhost:51295/api/Values/' + params.testid;
axios.get(url).then(res => {
const comments = res.data;
this.setState({ comments });
this.output = (
<div>
<ul>
{ this.state.comments.map
(comment =>
(<EditComment
QuizId = {comment.Rank}
FirstName = {comment.FirstName}
Comments = {comment.Comments}
TestId = {comment.TestimonialId}
/>)
)}
</ul>
</div>
);
//console.log("From did mount: " + this.currentComment);
this.forceUpdate();
});
}
render(){
return(
<div>
{this.output}
</div>
);
}
}
我为您创建了一个小应用程序来演示如何实现工作 react router v4
。
在每条路线上都有一个道具转储,你可以看到那里的参数是可见的。
在你的代码中,我不明白你为什么不使用 react-router v4
中的 Switch
,而且你的路线没有 exact
flag/prop。这样你就不会一个接一个地渲染你的组件视图了。
Link 到沙箱:https://codesandbox.io/s/5y9310y0zn
请注意,建议将withRouter
包裹在App组件周围,App组件不应包含<BrowserRouter>
。
审查您的代码
请注意,更新状态会触发组件的新渲染。
不要使用此处不需要的 this.forceUpdate()
,而是使用通过解析 Promise/axios 请求获得的值更新您的状态。
// Bad implementation of componentDidMount
// Just remove it
this.output = (
<div>
<ul>
{this.state.comments.map
(
comment =>
(<Comment
QuizId={comment.Rank}
FirstName={comment.FirstName}
Comments={comment.Comments}
TestId={comment.TestimonialId}
/>)
)}
</ul>
</div>
);
//console.log("From did mount: " + this.currentComment);
this.forceUpdate();
在 render 方法或任何其他辅助方法中移动循环函数,这里是使用辅助方法的代码。
renderComments() {
const { comments } = this.state;
// Just check if we have any comments
// Return message or just return null
if (!comments.length) return <div>No comments</div>;
// Move li inside loop
return (
<ul>
{comments.map(comment => (
<li key={comment.id}>
<Comment yourProps={'yourProps'} />
</li>
))}
</ul>
)
};
在您的初始状态中添加类似 isLoading
的内容。每次完成抓取或开始抓取时切换 isLoading 状态。
this.setState({ isLoading: true }); // or false
// Initial state or implement in constructor
state = { isLoading: true };
Render 方法将在我们每次加载内容时向我们显示加载,renderComments()
将 return 我们评论。我们得到干净且可读的代码。
render() {
if (isLoading) {
return <div>Loading...</div>
}
return (
<div>
{this.renderComments()}
</div>
);
}