Реагирует с response-router-dom 4 - Невозможно прочитать свойство 'params' из неопределенного

Я работал над изучением React, чтобы понять, соответствует ли он потребностям моей организации, так что нет необходимости говорить, что я новичок в этом. У меня есть пример приложения, над которым я работаю, чтобы увидеть, как оно работает. Я ознакомился с несколькими ответами здесь и не нашел ответа, который помог бы решить мою проблему.

Я сталкиваюсь с проблемой, когда я получаю "Uncaught (в обещании) TypeError: Невозможно прочитать свойство 'params' из undefined" в "componentDidMount()" at "const { match: { params } } = this.props;" Метод в компоненте ниже. У меня есть очень похожий компонент, который берет идентификатор из URL, используя тот же метод, и он работает нормально. Я не понимаю, почему один работает, а другой нет. Я, вероятно, просто делаю ошибку новичка где-то (возможно, больше, чем один), любые советы / ответы приветствуются.

Маршрут:

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

1 ответ

Решение

Я создал небольшое приложение для вас, чтобы продемонстрировать, как реализовать работу react router v4,

На каждом маршруте есть свалка реквизита, так как вы можете видеть, что параметры там видны.

В вашем коде я не вижу, почему вы не используете Switch от react-router v4, также ваши маршруты не имеют exact Флаг / проп. Таким образом, вы не будете визуализировать ваши представления компонентов один за другим.

Ссылка на песочницу: 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() вернет нам комментарии. Мы получаем чистый и читаемый код.

render() {
  if (isLoading) {
    return <div>Loading...</div>
  }

  return (
    <div>
      {this.renderComments()}
    </div>
  );
}
Другие вопросы по тегам