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>
  );
}