reactjs - React - Element type is invalid - how to debug this error? -
how can error message given react debugged ? figure out causing ? googled error seems caused different things.
invariant.js:38 uncaught invariant violation: element type invalid: expected string (for built-in components) or class/function (for composite components) got: object.
given code:
// @flow import react 'react'; import reactdom 'react-dom'; import { createstore , combinereducers} 'redux' import deepfreeze 'deepfreeze' import expect '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} > </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();
screenshot:
unfortunately speak javascript, not typescript (or whatever was), error pretty clear: tried render (an object) react wasn't expecting (because expects strings/functions).
i see 2 possibilities:
1) there bug in invariant.js
; since error came there problem, more ...
2) 1 of render methods includes (in return
value) object
unfortunately, you've discovered, react stack traces not particularly helpful. recommend commenting out render
methods of classes, 1 @ time, starting outermost 1 (which think filterlink
in case), , replace them temporarily simple return <div/>
.
then try produce error again. if still it, restore render
method , go same thing next class component chain. if not, you've found problematic render
. if can't see problem looking @ it, try logging every variable involved in (or, if use lodash/underscore, _.isobject(thatvariable)
) until find problem.
Comments
Post a Comment