2017-08-28 94 views
1

因此,今天下午我啓動了我用React前端製作的論文,一個Laravel後端。運行我的React dev服務器時出現的錯誤如下:未捕獲的錯誤:元素類型無效:預期爲字符串(對於內置組件)或類/函數(對於複合組件),但得到:未定義。你可能忘了您的組件從它的定義文件導出。反應:元素類型無效:期望一個字符串(對於內置組件)或一個類/函數(對於複合組件),但得到:undefined

JS Console Link

現在,這是一個相當龐大的項目,所以我來這裏的問題可能是很笨,經過一番研究,我真的來了在一些路由可能是問題,但我沒有嘗試解決這個問題。

我index.js:

import React from 'react'; 
import ReactDOM from 'react-dom'; 
import { Provider } from 'react-redux'; 
import { createStore } from 'redux'; 
import { Router, Route, browserHistory } from 'react-router'; 
import reducer from './reducers'; 

import App from './components/App'; 
import SignIn from './components/SignIn'; 
import SignUp from './components/SignUp'; 
import BoardView from './components/BoardView'; 
import ProjectView from './components/ProjectView'; 
import SprintView from './components/SprintView'; 
import ListView from './components/ListView'; 
import SprintChart from './components/Chart'; 


const store = createStore(reducer); 

function requireAuthentication(nextState, replace) { 
    if(!isUserAuthenticated() || !checkNewProjectStorage()) { 
     console.log('nextstate', nextState); 
     replace({ 
      pathname: '/signin', 
      state: { nextPathname: nextState.location.pathname } 
     }) 
    } 
} 

function isUserAuthenticated() { 
    var authenticated = false; 

    if(localStorage.getItem('token')) { 
     authenticated = true; 
    } 

    return authenticated; 
} 

function checkNewProjectStorage() { 
    var userIdStored = false; 

    if(localStorage.getItem('userId')) { 
     userIdStored = true; 
    } 

    return userIdStored; 
} 

ReactDOM.render(
    <Provider store={store}> 
     <Router history={browserHistory}> 
      <Route path="/" component={App} onEnter={requireAuthentication.bind(this)} /> 
      <Route path="/signin" component={SignIn} /> 
      <Route path="/signup" component={SignUp} /> 
      <Route path="/sprints" onEnter={requireAuthentication.bind(this)} component={SprintView} /> 
      <Route path="/chart" onEnter={requireAuthentication.bind(this)} component={SprintChart} /> 
      <Route path="/board" onEnter={requireAuthentication.bind(this)} component={BoardView} />    
      <Route path="/list" onEnter={requireAuthentication.bind(this)} component={ListView} /> 
     </Router> 
    </Provider>, 
    document.getElementById('root') 
) 

我App.jsx:

import React, { Component } from 'react'; 
import { browserHistory } from 'react-router'; 
import { Dropdown, Button, NavItem, Col, Card } from 'react-materialize'; 
import logo from '../images/scrumtastic_logo_white.png'; 
import axios from 'axios'; 
import { BASE_URL } from '../constants'; 
import Toast from './Toast' 
import '../App.css'; 
import ReactConfirmAlert, { confirmAlert } from 'react-confirm-alert'; 
import 'react-confirm-alert/src/react-confirm-alert.css'; 

class App extends Component { 
    constructor(props) { 
     super(props); 
     this.state = { 
      'userId': '', 
      'email': '', 
      'token': '', 
      'projects': [], 
      'projectId': '', 
      'editingMode': false, 
      'name': null, 
      'newName': '', 
      'description': null, 
      'newDesc': '', 
      'showEditingMode': -1, 
      'clickedProject': null, 
      'error': [], 
      'newProjectBool': false 
     } 
    } 

    componentWillMount() { 

     let email = localStorage.getItem('email'); 
     let token = localStorage.getItem('token'); 
     let userId = localStorage.getItem('userId'); 
     this.setState({'email': email, 'token': token, 'userId': userId}); 
    } 

    componentDidMount() { 
     const token = 'Bearer ' + this.state.token 

     axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 
     axios.defaults.headers.common['Authorization'] = token 
     axios.get(BASE_URL + '/users/' + this.state.userId + '/projects') 
      .then((data) => { 
       let userProjects = []; 
       data.data[0].projects.forEach((project) => { 
        userProjects.push(project); 
       }) 
       this.setState({'projects': userProjects}); 
      }) 
      .catch((error) => { 
       this.setState({error}); 
      }) 
    } 

    renderErrors() { 
     let errors = []; 
     if(this.state.error.response && this.state.error.response.data.error) 
     { 
      let errorArray = this.state.error.response.data.error; 
      let i = 0; 
      for(var key in errorArray) { 
       if(errorArray.hasOwnProperty(key)) { 
        errors.push(<p className="errorMessage" key={"error_" + i}>{errorArray[key][0]}</p>); 
       } 
       i++; 
      } 
     } 

     return <div className="center-align-error">{errors}</div> 
    } 

    logOut() { 
     const token = 'Bearer ' + this.state.token 

     axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 
     axios.defaults.headers.common['Authorization'] = token 
     axios.post(`${BASE_URL}/logout`, { 
      'email': this.state.email, 
     }) 
      .then((data) => { 
       if(data.status === 200) { 
        localStorage.removeItem('token') 
        localStorage.removeItem('email') 
        let t = new Toast("Succesfully logged out!", 2500) 
        t.Render(); 
        setTimeout(() => {browserHistory.push('/signin')}, 2500) 
       } 
      }) 
      .catch((error) => { 
       this.setState({error}); 
      }) 
    } 

    renderProjects() { 
     const projects = this.state.projects; 
     return (
      <ul> 
       { 
        projects.map((project) => { 
         return (
          <Col key={project.id} m={6} s={12}> 
           {(!this.state.editingMode && (this.state.clickedProject === null)) || (!this.state.editingMode && (this.state.clickedProject === project.id)) || (!this.state.editingMode && (this.state.clickedProject !== project.id)) || (this.state.editingMode && (this.state.clickedProject !== project.id)) ? <Card key={project.id} style={{backgroundColor: '#fff'}} textClassName="grey-text text-darken-4" title={project.name} actions={[<a style={{color: 'white', fontWeight: 'bold', cursor: 'pointer'}} key="Details Project" onClick={() => {this.projectView(project.id, project.name)}}>View Backlog</a>]}> 
            <p>{project.description}</p> 
            <a key="Delete Project" onClick={() => {this.confirm(project.id)}} style={{cursor: 'pointer'}}><i className="material-icons small" style={{color: '#a6262c', float: 'right'}}>delete_forever</i></a> 
            <a key="Edit Project" onClick={() => {this.editProject(project.id, project.name, project.description)}} style={{cursor: 'pointer'}}><i className="material-icons small" style={{color: '#2633a6', float: 'right'}}>mode_edit</i></a> 
           </Card> : 
           <Card key={project.id} style={{backgroundColor: '#fff', height: '280px'}} textClassName="grey-text text-darken-4"> 
            <form className="col s8"> 
             <div className="row"> 
              <div className="input-field col s12"> 
               <input 
                className="validate" 
                id="name" 
                type="text" 
                onChange={event => this.setState({name:event.target.value})} 
               /> 
               <label htmlFor="name"><b>Name:</b> {project.name}</label> 
              </div> 
             </div> 
             <div className="row"> 
              <div className="input-field col s12"> 
               <textarea 
                className="materialize-textarea" 
                id="description" 
                type="text" 
                onChange={event => this.setState({description:event.target.value})} 
               /> 
               <label htmlFor="description"><b>Description:</b> {project.description}</label> 
              </div> 
             </div> 
            </form> 
            <a onClick={() => {this.editProject(project.id)}} style={{cursor: 'pointer'}}><i className="material-icons small" style={{color: '#2633a6', float: 'right'}}>mode_edit</i></a> 
           </Card>} 
          </Col>  
         ) 
        }) 
       } 
      </ul> 
     ) 
    } 

    editProject(projectId, projectName, projectDescription) { 

     if(this.state.editingMode === true) { 
      const token = 'Bearer ' + this.state.token; 
      let newName = this.state.newName; 
      let newDesc = this.state.newDesc; 
      let projects = this.state.projects; 

      if(this.state.name) { 
       newName = this.state.name 
      } 

      if(this.state.description) { 
       newDesc = this.state.description 
      } 

      axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 
      axios.defaults.headers.common['Authorization'] = token 
      axios.put(`${BASE_URL}/projects/${projectId}`, { 
       'name': newName, 
       'description': newDesc 
      }) 
       .then((data) => { 
        for (var i=0; i < projects.length; i++) { 
         if (projects[i].id === projectId) { 
          projects[i].name = newName; 
          projects[i].description = newDesc; 
          this.setState({'projects': projects}); 
         } 
        } 
       }) 
       .catch((error) => { 
        this.setState({error}); 
       }) 
     } 
     else { 
      this.setState({'newName': projectName, 'newDesc': projectDescription}); 
     } 

     if(projectId) { 
      this.setState({'clickedProject': projectId}); 
     } 
     this.setState({'editingMode': !this.state.editingMode}); 
    } 

    confirm(projectId) { 
     confirmAlert({     
      message: 'Are you sure you want to delete this project?',    
      confirmLabel: 'Delete',       
      cancelLabel: 'Cancel',       
      onConfirm:() => this.deleteProject(projectId) 
      }) 
    } 

    deleteProject(projectId) { 

     const token = 'Bearer ' + this.state.token 
     let projects = this.state.projects; 
     axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 
     axios.defaults.headers.common['Authorization'] = token 
     axios.delete(BASE_URL + '/projects/' + projectId) 
      .then((data) => { 
       this.searchAndDeleteProjectFromState(projectId, projects); 
      }) 
      .catch((error) => { 
       this.setState({error}); 
      }) 
    } 

    searchAndDeleteProjectFromState(keyName, array) { 
     for (var i=0; i < array.length; i++) { 
      if (array[i].id === keyName) { 
       delete array[i] 
       this.setState({'projects': array}); 
       let t = new Toast("Succesfully deleted project!", 2500) 
       t.Render(); 
      } 
     }  
    } 

    projectView(projectId, projectName) { 
     localStorage.setItem('projectId', projectId); 
     localStorage.setItem('projectName', projectName); 
     browserHistory.push('/projects'); 
    } 

    newProject() { 
     const token = 'Bearer ' + this.state.token 
     let projects = this.state.projects; 

     axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest'; 
     axios.defaults.headers.common['Authorization'] = token 
     axios.post(`${BASE_URL}/projects`, { 
      'name': this.state.name, 
      'description': this.state.description, 
      'user_id': this.state.userId 
     }) 
      .then((data) => { 
       projects.push(data.data); 
       this.setState({projects: projects}); 
       this.setState({newProjectBool: false}); 
      }) 
      .catch((error) => { 
       this.setState({error}); 
      }) 
    } 

    setNewProjectBool() { 
     this.setState({newProjectBool: true}) 
    } 

    renderNewProject() { 
     return (
      <Col m={6} s={12}> 
       { (!this.state.newProjectBool) ? 
       <Card key="New Project" style={{backgroundColor: '#fff'}} textClassName="grey-text text-darken-4" actions={[<a key="New Project" style={{cursor: 'pointer', color: 'white', fontWeight: 'bold'}} onClick={() => this.setNewProjectBool()}>+ Make new project</a>]}> 
        <div key="New Project" style={{fontSize: '20px'}}>[Your new project will appear here]</div> 
       </Card> : 
       <Card key="New Project" style={{backgroundColor: '#fff', height: '280px'}} textClassName="grey-text text-darken-4"> 
       <form className="col s8"> 
        <div className="row"> 
         <div className="input-field col s12"> 
          <input 
           className="validate" 
           id="name" 
           type="text" 
           onChange={event => this.setState({name:event.target.value})} 
          /> 
          <label htmlFor="name"><b>Project Name</b></label> 
         </div> 
        </div> 
        <div className="row"> 
         <div className="input-field col s12"> 
          <textarea 
           className="materialize-textarea" 
           id="description" 
           type="text" 
           onChange={event => this.setState({description:event.target.value})} 
          /> 
          <label htmlFor="description"><b>Project Description</b></label> 
         </div> 
        </div> 
       </form> 
       <a onClick={() => {this.newProject()}} style={{cursor: 'pointer'}}><i className="material-icons small" style={{color: '#2ca626', float: 'right'}}>add_box</i></a> 
       </Card> 
       } 
      </Col> 
     ) 
    } 

    render() { 
     return (
      <div> 
       <nav className="teal lighten-3"> 
        <div className="nav-wrapper"> 
        <a className="brand-logo" href="/"><img className="nav-logo" src={logo} alt="logo"/></a> 
         <ul id="nav-mobile" className="right hide-on-med-and-down" style={{marginRight: '10px'}}> 
          <i className="material-icons" style={{height: 'inherit', lineHeight: 'inherit', float: 'left', margin: '0 30px 0 0', width: '2px'}}>perm_identity</i> 
          <Dropdown trigger={ 
           <Button style={{display: 'inline'}}>{this.state.email}</Button> 
           }> 
           <NavItem onClick={this.logOut.bind(this)}><i className="material-icons">input</i>Log Out</NavItem> 
           <NavItem divider /> 
          </Dropdown> 
         </ul> 
        </div> 
       </nav> 
       <div className="row"> 
        <div className="col s2"/> 
        <div className="col s8"> 
         <h2 style={{color: '#26a69a'}}>Projects</h2> 
         { 
          this.renderProjects() 
         } 
         {this.renderNewProject()} 
        </div> 
        <div className="col s2"/> 
       </div> 
       <div className="row"> 
        <div className="col s2" /> 
        <div className="col s8"> 
         {this.renderErrors()} 
        </div> 
        <div className="col s2" /> 
       </div> 
      </div>  
     ) 
    } 
} 

export default App; 

如果你想辦理其他成分,我的項目託管在GitHub上:Dissertation Project

會如果有人能夠幫助我,那就意味着我的世界,因爲我需要在3天內做完演講。

+0

你檢查了每個組件,看看你是否錯過了導入?它看起來像你可能正在使用一個組件,但忘記將它導入到某個文件中。你是否嘗試過使用Chrome的堆棧跟蹤來查看錯誤發生的位置? – Demon

+0

通過所有組件,我一直無法找到一個未導入的組件,不知道如何使用鉻的堆棧跟蹤作爲錯誤來自節點模塊,所以不知道如何從那裏跟蹤 – Pjai1

回答

1

我檢查了你的項目,看到文件'/src/components/BoardView.jsx'here)你的類名仍然是App。這可能是問題,因爲沒有BoardView組件導入。

+0

這是非常真實的謝謝,我不確定我是如何忽略這一點的,但這不能解決它。 – Pjai1

+0

可能有類似的問題。請檢查組件上的所有導出。 – bennygenel

+0

@ Pjai1我克隆了你的項目。我發現還有另外一個問題。 [Here](https://github.com/Pjai1/Scrumtastic/blob/33b9d498df418be07099f6be2001ea02544be3ee/frontend/scrumtastic/src/components/SprintView.jsx#L96)有一些意想不到的線路。當我清除這些行時,它的工作沒有錯誤。 – bennygenel

相關問題