错误:元素类型无效:在尝试更新状态时,应在反应中出现字符串

Posted

技术标签:

【中文标题】错误:元素类型无效:在尝试更新状态时,应在反应中出现字符串【英文标题】:Error: Element type is invalid: expected a string in react ,when trying to update state 【发布时间】:2020-10-22 21:14:13 【问题描述】:

从 fetch 更新状态时出现此错误。

错误:元素类型无效:应为字符串(对于内置组件)或类/函数(对于复合组件),但得到:未定义。您可能忘记从定义组件的文件中导出组件,或者您可能混淆了默认导入和命名导入。

这是我下面的代码

import React  from "react"
import useState from "react"
import 
  Button,
  Progress,
  UncontrolledDropdown,
  DropdownMenu,
  DropdownToggle,
  DropdownItem,
  Input,
Badge,
Row,
Col,
 ListGroup,
  ListGroupItem
 from "reactstrap";
import Draggable from 'react-draggable'
import StatisticsCard from "../../components/@vuexy/statisticsCard/StatisticsCard"
import DataTable from "react-data-table-component"
import classnames from "classnames"
import ReactPaginate from "react-paginate"
import  history  from "../../history"
import 
  Edit,
  Trash,
  ChevronDown,
  Plus,
  Check,
  ChevronLeft,
  ChevronRight,
 Monitor,
  UserCheck,
  Mail,
  Eye,
  MessageSquare,
  ShoppingBag,
  Heart,
  Smile,
  Truck,
  Cpu,
  Server,
  Activity,
  AlertOctagon,
CreditCard,
Share,
Image
 from "react-feather"
import  connect  from "react-redux"
import 
  getData,
  getInitialData,
  deleteData,
  updateData,
  addData,
  filterData
 from "../../redux/actions/data-list/"
import Sidebar from "./DataListSidebar"
import Chip from "../../components/@vuexy/chips/ChipComponent"
import Checkbox from "../../components/@vuexy/checkbox/CheckboxesVuexy"

import "../../assets/scss/plugins/extensions/react-paginate.scss"
import "../../assets/scss/pages/data-list.scss"
import  Modal, ModalHeader, ModalBody, ModalFooter  from 'reactstrap';
import NumberFormat from 'react-number-format';
import $ from 'jquery'
import tc from 'thousands-counter';
 

 

class DataListConfig extends React.Component  


 constructor(props)
 super(props)
 
 
  this.state = 
    data: [],
    campaigns: [],
    tt: 0,
    totalPages: 0,
    currentPage: 0,
    columns: [
      
        name: "Name",
        selector: "name",
        sortable: true,
        cell: row => (
          <p title=row.name className="text-truncate text-bold-500 mb-0">
            sessionStorage.Name
          </p>
        )
      ,
       
        name: "Title",
        selector: "title",
        sortable: true,
        cell: row => (
          <p className="text-bold-500 text-truncate mb-0">row.title</p>
        )
      ,
      
            
        name: "Total Donation",
        selector: "totaldonor",
        sortable: true,
        cell: row => (
          <p className="text-bold-500 text-truncate mb-0"> <NumberFormat value=row.amounts displayType='text' thousandSeparator=true prefix='₦' /></p>
        )
      ,
      
        name: "Status",
        selector: "status",
        sortable: true,
        cell: row => (
          <Badge
            color=row.status === null || row.status === '' ? "light-danger" : "light-success"
            pill>
           row.status === null || row.status === '' ? "Pending":"Active"
          </Badge>
        )
      ,
      
       
        name: "Start Date",
        selector: "startdate",
        sortable: true,
        cell: row => <p className="text-bold-500 mb-0">row.startdate</p>
      ,
      
        name: "Category",
        selector: "category",
        sortable: true,
        cell: row => <p className="text-bold-500 mb-0">row.category</p>
      ,
      
        name: "Actions",
        sortable: true,
        cell: row => (
        <this.ActionsComponent
            row=row
            getData=this.props.getData
            parsedFilter=this.props.parsedFilter
            currentData=this.handleCurrentData
            deleteRow=this.handleDelete
          />

        )
      
    ],
    allData: [],
    value: "",
    comments:[],
    rowsPerPage: 4,
    sidebar: false,
    currentData: null,
    selected: [],
    totalRecords: 0,
    sortIndex: [],
    addNew: ""
  
  const headers =  'Content-Type': 'application/json' , 'Authorization':`Bearer $sessionStorage.jwt`
    fetch(' ',  headers )
        .then(response => response.json())
        .then(data => 
        
    
   
             
    this.setState( data: data.posts )
 
).catch((error) => 
  console.log(error)
);


 
 
  componentDidMount()

 
function ActionsComponent(props) 


        



 
  const 
    buttonLabel,
    className
   = props;
const [modal, setModal] = useState(false);
const [modal2, setModal2] = useState(false);
  const [items, setItems] = useState([]);
 const [comments,setCom] = useState([])
 
 const Details = (id)=> 
 
 $.post(' ',
 
 postid: id
 ,function(data,status)
  
setItems([
      ...items,
      
        datas: data
       
      
    ]);

  
 )
 

  
 
 

  $.post(' ',
 
 postid: props.row.id
 ,function(data,status)
   
 
this.setState(commets: data)

  
 )
 
 


 
 let datas
 datas = totaldonors: "",totalcomments:""
  items.map((key)=>
 datas = key.datas
  )
 
const dashdata = datas
 


  const toggleModal = (id) => setModal(!modal); ;
 const toggleModal2 = (id) => setModal2(!modal2); ;
 
  return (
  

  <div>
    <Draggable>
 <Modal
        isOpen=modal
        toggle=toggleModal
        className="modal-dialog-centered"
        backdrop=false
      >
        <ModalHeader toggle=toggleModal>
          Campaign Dashboard!
        </ModalHeader>
        <ModalBody className="modal-dialog-centered">
  
 <div className="container">
  <div className="row">
    <div className="col-sm">
    <StatisticsCard
              hideChart
              iconBg="primary"
              icon=<CreditCard className="primary" size=22 />
              stat=tc(dashdata.totaldonors)
              statTitle="Total Donors"
            />
    </div>
    <div className="col-sm">
    <StatisticsCard
              hideChart
              iconBg="primary"
              icon=<Share className="primary" size=22 />
              stat="36.9k"
              statTitle="Total Shares"
            />
    </div>
    <div className="col-sm">
    <StatisticsCard
              hideChart
              iconBg="primary"
              icon=<MessageSquare className="primary" size=22 />
              stat=tc(dashdata.totalcomments)
              statTitle="Total Comments"
            />
    </div>
<div className="container" style='max-height':'300px','overflow-y': 'scroll'>

 
</div>
  </div>

</div>


  
        </ModalBody>
        <ModalFooter>
          <Button color="primary">
         Request Withdrawal
          </Button>" "
        </ModalFooter>
      </Modal>

                    </Draggable>
                    
                    
                       

    <div className="data-list-action">
    " "
    " "
      <Edit
        className="cursor-pointer mr-1"
        size=20
        onClick=() => 
          return props.currentData(props.row)
        
      />

 <Activity
        className="cid cursor-pointer mr-1"
        size=20
          onClick=()=>return toggleModal(),Details(props.row.id);
      />
      
    </div>

</div>

  )


 
     



  thumbView = this.props.thumbView

 

 

  componentDidUpdate(prevProps, prevState) 
    if (this.thumbView) 
      this.thumbView = false
      let  columns =  [
      
        name: "Name",
        selector: "name",
        sortable: true,
        cell: row => (
          <p title=row.name className="text-truncate text-bold-500 mb-0">
            sessionStorage.Name
          </p>
        )
      ,
       
        name: "Title",
        selector: "title",
        sortable: true,
        cell: row => (
          <p className="text-bold-500 text-truncate mb-0">row.title</p>
        )
      ,
      
        name: "Status",
        selector: "status",
        sortable: true,
        cell: row => (
          <Badge
            color=row.status === null || row.status === '' ? "light-danger" : "light-success"
            pill>
           row.status === null || row.status === '' ? "Pending":"Active"
          </Badge>
        )
      ,
            
        name: "Total Donation",
        selector: "totaldonor",
        sortable: true,
        cell: row => (
          <p className="text-bold-500 text-truncate mb-0">row.amounts</p>
        )
      ,
      
       
        name: "Start Date",
        selector: "startdate",
        sortable: true,
        cell: row => <p className="text-bold-500 mb-0">row.startdate</p>
      ,
      
        name: "Category",
        selector: "category",
        sortable: true,
        cell: row => <p className="text-bold-500 mb-0">row.category</p>
      ,
       
      
          name: "Actions",
          sortable: true,
          cell: row => (
            <this.ActionsComponent
              row=row
              getData=this.props.getData
              parsedFilter=this.props.parsedFilter
              currentData=this.handleCurrentData
              deleteRow=this.handleDelete
            />
             
          )
        
      ]
      this.setState( columns )
    
  

  handleFilter = e => 
    this.setState( value: e.target.value )
    this.props.filterData(e.target.value)
  

  handleRowsPerPage = value => 
    let  parsedFilter, getData  = this.props
    let page = parsedFilter.page !== undefined ? parsedFilter.page : 1
    history.push(`/funding/?page=$page&perPage=$value`)
    this.setState( rowsPerPage: value )
    getData( page: parsedFilter.page, perPage: value )
  

  handleSidebar = (boolean, addNew = false) => 
    this.setState( sidebar: boolean )
    if (addNew === true) this.setState( currentData: null, addNew: true )
  

  handleDelete = row => 
    this.props.deleteData(row)
    this.props.getData(this.props.parsedFilter)
    if (this.state.data.length - 1 === 0) 
      let urlPrefix = this.props.thumbView
        ? "/funding/"
        : "/funding/"
      history.push(
        `$urlPrefixlist-view?page=$parseInt(
          this.props.parsedFilter.page - 1
        )&perPage=$this.props.parsedFilter.perPage`
      )
      this.props.getData(
        page: this.props.parsedFilter.page - 1,
        perPage: this.props.parsedFilter.perPage
      )
    
  

  handleCurrentData = obj => 
    this.setState( currentData: obj )
    this.handleSidebar(true)
  

  handlePagination = page => 
    let  parsedFilter, getData  = this.props
    let perPage = parsedFilter.perPage !== undefined ? parsedFilter.perPage : 4
 
    let urlPrefix = this.props.thumbView
      ? "/funding/b"
      : "/funding/"
    history.push(
      `$urlPrefix?page=$page.selected + 1&perPage=$perPage`
    )
    getData( page: page.selected + 1, perPage: perPage )
 
 
    this.setState( currentPage: page.selected )
  

  render() 
    let 
      columns,
      data,
      allData,
      totalPages,
      value,
      rowsPerPage,
      currentData,
      sidebar,
      totalRecords,
      sortIndex
     = this.state
    

    return (
      <div
        className=`data-list $
          this.props.thumbView ? "thumb-view" : "list-view"
        `>
<CustomHeader
handleSidebar=this.handleSidebar
              handleFilter=this.handleFilter
              handleRowsPerPage=this.handleRowsPerPage
              rowsPerPage="5"
              total=totalRecords
              index=sortIndex
/>
        <DataTable
          columns=columns
          data=data
          pagination

          noHeader
          
          selectableRows
          responsive
          pointerOnHover
          selectableRowsHighlight
          onSelectedRowsChange=data =>
            this.setState( selected: data.selectedRows )
          
          customStyles=selectedStyle
          subHeaderComponent=
            <CustomHeader
              handleSidebar=this.handleSidebar
              handleFilter=this.handleFilter
              handleRowsPerPage=this.handleRowsPerPage
              rowsPerPage="5"
              total=totalRecords
              index=sortIndex
            />
          
          sortIcon=<ChevronDown />
          selectableRowsComponent=Checkbox
          selectableRowsComponentProps=
            color: "primary",
            icon: <Check className="vx-icon" size=12 />,
            label: "",
            size: "sm"
          
        />
        <Sidebar
          show=sidebar
          data=currentData
          updateData=this.props.updateData
          addData=this.props.addData
          handleSidebar=this.handleSidebar
          thumbView=this.props.thumbView
          getData=this.props.getData
          dataParams=this.props.parsedFilter
          addNew=this.state.addNew
        />
        <div
          className=classnames("data-list-overlay", 
            show: sidebar
          )
          onClick=() => this.handleSidebar(false, true)
        />
      </div>
    )
  


const mapStateToProps = state => 
  return 
    dataList: state.dataList
  


const   handleSidebar = (boolean, addNew = false) => 
    this.setState( sidebar: boolean )
    if (addNew === true) this.setState( currentData: null, addNew: true )
  

export default connect(mapStateToProps, 
  getData,
  deleteData,
  updateData,
  addData,
  getInitialData,
  filterData
)(DataListConfig)

出于安全目的,我删除了我的 api 端点

bug image

【问题讨论】:

【参考方案1】:

DataListConfig 组件尝试渲染&lt;this.ActionsComponent&gt;。因为ActionsComponent 是在componentDidMount 方法内部定义的,而不是在类级别,所以this.ActionsComponent 是未定义的。导致错误的原因。

尽管在另一个组件中定义一个组件是一个坏主意。在类组件的类中作为字段,这将意味着该类组件的每个实例will have their own version of the function component。这充其量闻起来很腥,而且不是很像 React。

ActionsComponent 完全移出DataListConfig 组件,并通过其道具传递所需的数据。

function ActionsComponent(props) 
  // ...


class DataListConfig extends React.Component 
  // ...

【讨论】:

如何在函数内部设置状态,可以吗? @silexsecurelab 您传递了一个回调函数,该函数通过 props 将父组件中的状态设置给组件。有关示例,请参见React tutorial(尤其是它们将onClick 传递给&lt;Square&gt; 的部分)

以上是关于错误:元素类型无效:在尝试更新状态时,应在反应中出现字符串的主要内容,如果未能解决你的问题,请参考以下文章

反应错误:元素类型无效:需要一个字符串

反应本机错误!元素类型无效:应为字符串或类/函数,但得到:未定义

使用多个(最新)第 3 方反应库反应“未捕获的不变违规:元素类型无效”

在反序列化过程中出现下一个异常:“源数据中的无效字段:0”。如何找出源代码中的原因/错误位置?

尝试在反应组件的返回中使用 setstate 更新状态并获得“最大更新深度超出错误”?

React.createElement:类型无效(地图)