A
A
AplexPlex2018-07-11 11:50:24
typescript
AplexPlex, 2018-07-11 11:50:24

Why does React Router's this.props.match.param not exist?

Can't pass parameters to url when using react-router.
Github

<Switch>
      <Route exact path='/:id' component={ HocLoginComponet(LoginPage) } />
      <Route path='/student/test/:id' component={RouterComponentHOC(withAppLayout(<TesterForm />))}/>
      <Route path='/student' component={ RouterComponentHOC(withAppLayout(StudentForm)) }/>
      <Route path='/admin' component={ RouterComponentHOC(AdminPage)} />
      <Route path='/teacher' component={ RouterComponentHOC(TeacherPage)} />
      <Route path='*' component={NotFoundPage}/>
    </Switch>

Here I specify the dynamic path to the TesterForm component in which the id is passed to the url and should be defined as a passed parameter.
RouterComponentHOC
RouterComponentHOC
Это компонент для проверки авторизован пользователь или нет, и если нет отправляет на страницу авторизации.
Код RouterComponentHOC
import * as PropTypes from 'prop-types';
import * as React from 'react';
import { asyncComponent } from 'react-async-component';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { AuthActions, IDispatchProps } from '../actions/authActions';
import { getRoleRequestFetch } from '../api/hocAuthApi';
import { IAppState } from '../types';
import { LoadingComponent } from './LoadingComponent';

const HocComponet = (Component: any) => {
  return asyncComponent({
    resolve: async () => {
      const data = await getRoleRequestFetch();
      interface IStateProps {
        authState: boolean;
        role_type: string;
      }

      type TProps = IDispatchProps & IStateProps;
      class RetComp extends React.Component<TProps> {
        public static contextTypes = {
          router: PropTypes.object,
        };
        constructor(props: any, context: any) {
          super(props, context);
        }
        public componentWillMount() {
          this.props.authActions.onUpdateAuth(data.auth, data.role_type);
        }
        public onRedirect = (url: string) => {
          return document.location.replace(url);
        }
        public onRoute = () => {
          if (data.role_type === `/${document.location.pathname.split('/')[1]}`) {
            return <Component/>;
          }
          return this.context.router.history.push('/404');
        }
        public render() {
          return <div> {
            !data.auth ? this.onRedirect('/') : this.onRoute()
          } </div>;
        }
      }
      function mapStateToProps(state: IAppState): IStateProps {
        return {
          authState: state.commonReducer.authState,
          role_type: state.commonReducer.role_type,
        };
      }

      function mapDispatchToProps(dispatch: Dispatch<IDispatchProps>): IDispatchProps {
        return {
          authActions: new AuthActions(dispatch),
        };
      }
      return connect(mapStateToProps, mapDispatchToProps)(RetComp);
    },
    LoadingComponent: () => <LoadingComponent/>,
  });
};
export default HocComponet;

withAppLayout
router.tsx
const withAppLayout = (Component: any) => (props: any) => <StudentPage><Component {...props} /></StudentPage>;

StudentPage.tsx
import * as React from 'react';

export class StudentPage extends React.Component {
  public render() {
    return <div className='container'>
      {this.props.children}
    </div>;
  }
}


But I don’t understand how to get these parameters. in the component located at the given url, it gives an error that this.props.match does not exist.
import * as PropTypes from 'prop-types';
import * as React from 'react';
import { connect } from 'react-redux';
import { Dispatch } from 'redux';
import { IDispatchProps, StudentActions } from '../../actions/studentActions';
import { IAppState } from '../../types';
import { AnswerForm } from './AnswerForm';

interface IStateProps {
  serverConnectError: boolean;
  serverDataError: boolean;
  authState: boolean;
  activeTest: number;
  testIssuesList: [object];
  testState: [object];
}

type TProps = IDispatchProps & IStateProps;

class TesterForm extends React.Component<TProps> {
  public static contextTypes = {
    router: PropTypes.object,
  };
  constructor(props: any, context: any) {
    super(props, context);
  }
  public componentWillMount() {

    this.props.studentActions.getTestIssues(this.props.activeTest);
  }

  public render() {
    return(
      <div className='row'>
        <AnswerForm />
      </div>
    );
  }
}

function mapStateToProps(state: IAppState): IStateProps {
  return {
    serverConnectError: state.commonReducer.serverConnectError,
    serverDataError: state.commonReducer.serverDataError,
    authState: state.commonReducer.authState,
    activeTest: state.studentReducer.activeTest,
    testIssuesList: state.studentReducer.testIssuesList,
    testState: state.studentReducer.testState,
  };
}

function mapDispatchToProps(dispatch: Dispatch<IDispatchProps>): IDispatchProps {
  return {
    studentActions: new StudentActions(dispatch),
  };
}

const connectApp = connect(mapStateToProps, mapDispatchToProps)(TesterForm);

export {connectApp as TesterForm};

Answer the question

In order to leave comments, you need to log in

2 answer(s)
A
Anton Spirin, 2018-07-11
@AplexPlex

You are not passing props to the component.

public onRoute = () => {
  if (data.role_type === `/${document.location.pathname.split('/')[1]}`) {
    return <Component/>;  // тут ничего не передается
  }
  return this.context.router.history.push('/404');
}

this is how it should work:
public onRoute = () => {
  if (data.role_type === `/${document.location.pathname.split('/')[1]}`) {
    return <Component {...this.props} />;
  }
  return this.context.router.history.push('/404');
}

As an alternative to HOC, you can wrap a Route using composition.
Why you use context in a child router component is a mystery.

A
AplexPlex, 2018-07-11
@AplexPlex

Other than that, I was trying to get the data wrong.
I tried to get data via.
But match didn't exist. I don't know why, but when using connect Redux, parameters are passed through it.

import * as PropTypes from 'prop-types';
import * as React from 'react';
import { connect } from 'react-redux';
import { RouteComponentProps } from 'react-router-dom';
import { Dispatch } from 'redux';
import { IDispatchProps, StudentActions } from '../../actions/studentActions';
import { IAppState } from '../../types';
import { AnswerForm } from './AnswerForm';

interface IStateProps {
  serverConnectError: boolean;
  serverDataError: boolean;
  authState: boolean;
  activeTest: number;
  testIssuesList: [object];
  testState: [object];
  id: number;
}

interface IRouterProps {
  id: number;
}

type IProps = IStateProps & IRouterProps;

type TProps = IDispatchProps & IStateProps;

class TesterForm extends React.Component<TProps> {
  public static contextTypes = {
    router: PropTypes.object,
  };
  constructor(props: any, context: any) {
    super(props, context);
  }
  public componentWillMount() {
    alert(this.props.id);
    this.props.studentActions.getTestIssues(this.props.activeTest);
  }

  public render() {
    return(
      <div className='row'>
        <AnswerForm/>
      </div>
    );
  }
}

function mapStateToProps(state: IAppState, ownProps: RouteComponentProps<IRouterProps>): IProps {
  return {
    serverConnectError: state.commonReducer.serverConnectError,
    serverDataError: state.commonReducer.serverDataError,
    authState: state.commonReducer.authState,
    activeTest: state.studentReducer.activeTest,
    testIssuesList: state.studentReducer.testIssuesList,
    testState: state.studentReducer.testState,
    id: ownProps.match.params.id, // Здесь передаются параметрвы
  };
}

function mapDispatchToProps(dispatch: Dispatch<IDispatchProps>): IDispatchProps {
  return {
    studentActions: new StudentActions(dispatch),
  };
}

const connectApp = connect(mapStateToProps, mapDispatchToProps)(TesterForm);

export {connectApp as TesterForm};

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question