0

I'm new to React and ES6, and am a bit stuck with react-router-dom. I'm currently either getting error messages or none of the information seems to be loading in. I'm using React 15.6.

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import App from './components/App';
import Vote from './components/Vote';
import Results from './components/Results';

ReactDOM.render(
  <Router>
    <App>
      <Route path="/" component={Vote} />
      <Route path="/results" component={Results} />
    </App>
  </Router>,
  document.getElementById('root')
);

If I have the two Route declarations in index.js, I am getting an error

Element type is invalid: expected a string (for built-in components) or a 
class/function (for composite components) but got: undefined. 
You likely forgot to export your component from the file it's defined in.

I think this means that this.props.children doesn't have a value, so it can't clone the route with the pair list correctly?

If I remove the one of the Route declarations, the page does successfully compile, but it's just empty. I added a line of text to the return() in Vote.jsx and it does output that, so the route is working correctly, just nothing is being outputted for the this.getPair() function.

React Page Compiled

It looks like App.jsx also loads correctly, as it I change the return in this file to output text, it does so.

As mentioned, I'm entirely green to this, so I'm hoping its something fairly simple, or just a misunderstanding of how everything stitches together.

App.jsx

import React from 'react';
import {List, Map} from 'immutable';

const pair = List.of('Item One', 'Item Two');
const tally = Map({'Item One': 5, 'Item Two': 4});

export class App extends React.PureComponent {
  render() {
    return (
      React.cloneElement(this.props.children, {pair: pair})
    )
  }
};

export default App;

Vote.jsx

import React from 'react';

export class Vote extends React.PureComponent {

  getPair() {
    return this.props.pair || [];
  }

  isDisabled() {
    return !!this.props.hasVoted;
  }

  hasVotedFor(entry) {
    return this.props.hasVoted === entry;
  }

  render() {
    return (
      <div className="voting">
        {this.getPair().map(entry =>
          <button key={entry} onClick={() => this.props.vote(entry)} disabled={this.isDisabled()}>
            <h1>{entry}</h1>
            {this.hasVotedFor(entry) ? <div className="label">Voted</div> : null}
          </button>
        )}
      </div>
    )
  }
};

export default Vote;

Results.jsx

import React from 'react';

export class Results extends React.PureComponent {

  getPair() {
    return this.props.pair || [];

  }

  getVotes(entry) {
    if (this.props.tally && this.props.tally.has(entry)) {
      return this.props.tally.get(entry);
    }

    return 0;
  }

  render() {
   return (
      <div className="results">
        {this.getPair().map(entry =>
          <div key={entry} className="entry">
            <h1>{entry}</h1>
            <div className="voteCount">
              {this.getVotes(entry)}
            </div>
          </div>
        )}
      </div>
    )
  }
};

export default Results;
10
  • 1
    are u using React 16 ? Commented Nov 14, 2017 at 13:02
  • 2
    Simple error in your first <Route/>'s component prop. Change Vote to Voting, or vice versa, to match your import statement. Commented Nov 14, 2017 at 13:09
  • 1
    Next step might be to try nesting the routes within a <Switch/> statement, seeing as giving the <App/> component one child seems to work. Commented Nov 14, 2017 at 13:27
  • 1
    Also, getPair() isn't bound to this. You might want to try calling it using an arrow function or binding it inside of your component's constructor() method. Commented Nov 14, 2017 at 13:33
  • 1
    You can also pass props directly to route components like so: <Route path="/" component={() => <Vote pair={pair}/>} />. It might be cleaner to declare the routes from inside of your <App/> component's file for the sake of passing data. Commented Nov 14, 2017 at 13:37

1 Answer 1

1

Arman Charan's comment about using a <Switch /> statement was the way that I got the routes to work and to stop receiving the mentioned error.

ReactDOM.render(
    <Router>
      <App>
        <Switch>
          <Route path="/" component={Vote} />
          <Route path="/results" component={Results} />
        </Switch>
    </Router>,
  document.getElementById('root')
);
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.