2016-11-17 3 views
4

Как это сообщение об ошибке, данное реакцией отладки? Чтобы выяснить, что на самом деле вызывает это? Я искал ошибку Google, но, похоже, это вызвано разными вещами.React - Тип элемента недействителен - как отладить эту ошибку?

invariant.js:38 Uncaught Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.

даваемый этим кодом:

// @flow 
import React from 'react'; 
import ReactDOM from 'react-dom'; 
import { createStore , combineReducers} from 'redux' 
import deepFreeze from 'deepfreeze' 
import expect from 'expect' 
var _ = require('lodash') 

type State$Todo = { 
    text:string; 
    completed:boolean; 
    id:number; 
}; 

class Todo { 
    static make(t:string,id:number):State$Todo{ 
    return {text:t,id:id,completed:false} 
    } 
    static toggle(t:State$Todo):State$Todo { 
    return {...t, completed:!t.completed}; 
    } 
}; 

type Action$SetVisibilityFilter = { 
    type:'SET_VISIBILITY_FILTER', 
    filter:State$VisibilityFilter 
}; 

type Action$ADD_TODO = { 
    type:'ADD_TODO', 
    text:string, 
    id:number 
}; 

type Action$TOGGLE_TODO = { type:'TOGGLE_TODO', id:number } 

type Action$Todo = Action$ADD_TODO | Action$TOGGLE_TODO 

type Action$App = Action$Todo | Action$SetVisibilityFilter 

type State$TodoList = State$Todo[]; 

type State$VisibilityFilter = 'SHOW_ACTIVE' | 'SHOW_ALL' | 'SHOW_COMPLETED' 

type State$App = { 
    todos:State$TodoList, 
    visibilityFilter:State$VisibilityFilter 
} 

const todosReducer = (state: State$TodoList=[], action: Action$App) :State$TodoList=>{ 
     switch (action.type){ 
     case 'ADD_TODO' : return [ ... state, Todo.make(action.text, action.id)]; 
     case 'TOGGLE_TODO': 
      const id=action.id; 
      return _.map(state, (td) => (td.id==id) ? Todo.toggle(td) : td); 
     default : return state; 
     } 
}; 

const visibilityFilterReducer = (state:State$VisibilityFilter = 'SHOW_ALL', action:Action$App) : State$VisibilityFilter => { 
    switch(action.type) { 
    case 'SET_VISIBILITY_FILTER': 
     return action.filter; 
    default : return state; 
    } 
} 

const todoApp = (state : State$App = {todos:[],visibilityFilter:'SHOW_ALL'}, action: Action$App) : State$App => { 
    return { todos: todosReducer(state.todos, action), visibilityFilter: visibilityFilterReducer(state.visibilityFilter,action) }; 
} 

//const todoApp =combineReducers({todos:todosReducer, visibilityFilter:visibilityFilterReducer}) 
const store = createStore (todoApp) 



type FilterLinkProps={ 
    filter:State$VisibilityFilter, 
    currentFilter:State$VisibilityFilter, 
    children:React$Element<*> 
}; 

const FilterLink = ({ 
    filter, 
    currentFilter, 
    children 
}:FilterLinkProps) => { 
    if(filter===currentFilter) { 
    return <span>{children}</span> 
    } 
    return (
    <a href='#' 
     onClick={e => { 
     e.preventDefault(); 
     store.dispatch(({ 
      type: 'SET_VISIBILITY_FILTER', 
      filter 
     }:Action$SetVisibilityFilter)); 
     }} 
    > 
    {children} 
    </a> 
); 
}; 

const getVisibleTodos = (
    todos:State$TodoList, 
    filter:State$VisibilityFilter 
) : State$TodoList => { 
    switch (filter) { 
    case ('SHOW_ALL' :State$VisibilityFilter): 
     return todos; 
    case ('SHOW_COMPLETED':State$VisibilityFilter): 
     return todos.filter(
     t => t.completed 
    ); 
    case ('SHOW_ACTIVE':State$VisibilityFilter): 
     return todos.filter(
     t => !t.completed 
    ); 
    default: 
     throw "undefined action" 
    } 
} 

let nextTodoId = 0; 
const TodoReactElement=(props:{onClick:Function,completed:boolean,text:string}) =>(
      <li onClick={props.onClick} 
       style ={{ textDecoration: props.completed ? 'line-through' : 'none'}} > 
       {props.text} 
      </li> 
); 

type TodoListReactComponentProps ={todos:State$TodoList,onTodoClick:Function} 

const TodoList =(props:TodoListReactComponentProps) =>(
    <ul> 
    {props.todos.map(todo=> 
     <TodoReactElement 
     key ={todo.id} 
     completed={todo.completed} 
     onClick={()=> props.onTodoClick(todo.id)} 
     text= {todo.text} > 
     </TodoReactElement>)} 
    </ul> 
) 


class TodoApp extends React.Component { 
    render() { 

    const todos : State$TodoList= this.props.todos; 
    const visibilityFilter :State$VisibilityFilter= 
      this.props.visibilityFilter; 
    const visibleTodos :State$TodoList = getVisibleTodos(
     todos, visibilityFilter); 

    return (
     <div> 
     <input ref ={ node => {this.input=node;} } /> 
     <button onClick={() => { 
      store.dispatch(({ 
      type: 'ADD_TODO', 
      text: 'Test'+this.input.value, 
      id: nextTodoId++ 
      } : Action$ADD_TODO)); 
      this.input.value=''; 
     }}> 
      Add Todo 
     </button> 
     <TodoList todos={visibleTodos} 
        onTodoClick={id=> store.dispatch(({type:'TOGGLE_TODO',id}:Action$TOGGLE_TODO))}> 
     </TodoList> 
     <p> 
      Show: 
      {' '} 
      <FilterLink 
      filter='SHOW_ALL' 
      currentFilter={visibilityFilter} 
      > 
      All 
      </FilterLink> 
      {' '} 
      <FilterLink 
      filter='SHOW_ACTIVE' 
      currentFilter={visibilityFilter} 
      > 
      Active 
      </FilterLink> 
      {' '} 
      <FilterLink 
      filter='SHOW_COMPLETED' 
      currentFilter={visibilityFilter} 
      > 
      Completed 
      </FilterLink> 
     </p> 

     </div> 
    ); 
    } 
} 
const root = document.getElementById('root') 
const render =() => { 
    ReactDOM.render(
    <TodoApp {...store.getState()} />,root 
); 
}; 

store.subscribe(render) 
render(); 

скриншот:

enter image description here

+0

, что в 'invariant.js', не в моем коде - как видно из скриншота – jhegedus

+0

ли это' {} 'props.text? Просто любопытно. –

ответ

3

К сожалению, я только говорю Javascript, а не машинописном (или независимо от того, что было), но ошибка сам по себе довольно ясен: вы пытались сделать что-то (объект), который React не ожидал (потому что он ожидает строки/func ЦИИ).

Я вижу две возможности:

1) есть ошибка в invariant.js; так как ошибка пришла оттуда, это может быть проблемой, но более вероятно ...

2) один из ваших методов отображения включает в себя (в значении return) объект

К сожалению, как вы обнаружили, Реагировать трассировки стека не всегда особенно полезны. Лично я бы рекомендовал просто комментировать методы render ваших классов по одному, начиная с самого дальнего (что я думаю, - FilterLink в вашем случае) и временно заменить их на return <div/>.

Затем попытайтесь снова произвести ошибку. Если вы все равно получите его, восстановите метод render и перейдите к следующему классу в цепочке компонентов. Если нет, вы нашли свой проблемный render. Если вы не можете сразу увидеть проблему, посмотрев на нее, попробуйте выполнить регистрацию каждой переменной, связанной с ней (или, если вы используете Lodash/Underscore, _.isObject(thatVariable)), пока не найдете проблему.

0

Вы указали здесь, что "дети" FilterLink в проп принимает только Реагировать элементы:

type FilterLinkProps={ 
    // ... snipped ... 
    children:React$Element<*> 
}; 

... но вы передаете не-React элементы (объекты, строки и т.д.). Вам нужно изменить тип prop на «React.PropTypes.node» вместо «React.PropTypes.element» (извините, я тоже не говорю об этом синтаксисе, но я вижу, что происходит, в основном)

0

Я думаю, что сообщение об ошибке довольно прямое, но в каком компоненте? Вот в чем вопрос. На самом деле, в callstack есть некоторые точки, имеющие некоторые родительские компоненты.

Добавить точку останова на instantiateReactComponent (instantiateReactComponent.js:74) и повторить попытку. Нажмите, чтобы mountComponent ...reactConciler.js... приведет вас к вызову internalInstance.mountComponent. и в innerInstance вы можете найти какой-то осмысленный тип элемента в _currentElement.type. Там вы можете найти ребенка с недопустимым типом.

_currentElement.type

Смежные вопросы