【问题标题】:Switching between components in React JS在 React JS 中的组件之间切换
【发布时间】:2016-03-08 18:39:36
【问题描述】:

我想创建一个包含 2 个组件的简单流程。第一个组件被渲染,我点击它上面的一个按钮,这个动作渲染第二个组件。单击第二个组件中的按钮,它应该切换回第一个,但是发生了错误:

警告:React.createElement:类型不应为 null、未定义、 布尔值或数字。它应该是一个字符串(对于 DOM 元素)或 ReactClass(用于复合组件)。检查渲染方法 exports.warning @react.js:20728ReactElementValidator.createElement @react.js:9853t.exports.React.createClass.render @ bundle.js:1ReactCompositeComponentMixin._renderValidatedComponentWithoutOwnerOrContext @react.js:6330ReactCompositeComponentMixin._renderValidatedComponent @react.js:6350wrapper @ react.js:12868ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6303ReactCompositeComponentMixin._performComponentUpdate @ react.js:6287ReactCompositeComponentMixin.updateComponent @ react.js:6216wrapper @ react.js:12868ReactCompositeComponentMixin.performUpdateIfNecessary @ react.js:6164ReactReconciler.performUpdateIfNecessary @ react.js:13667runBatchedUpdates@react.js:15356Mixin.perform@ react.js:17245Mixin.perform@react.js:17245assign.perform@ react.js:15313flushBatchedUpdates @ react.js:15374wrapper @ react.js:12868Mixin.closeAll@react.js:17311Mixin.perform@ react.js:17258ReactDefaultBatchingStrategy.batchedUpdates @ react.js:8842batchedUpdates @ react.js:15321ReactEventListener.dispatchEvent@react.js:10336 react.js:20250

未捕获的错误:不变违规:元素类型无效:预期 字符串(用于内置组件)或类/函数(用于复合 组件)但得到:对象。检查渲染方法 exports.invariant @ react.js:20250instantiateReactComponent @ react.js:18268ReactCompositeComponentMixin._updateRenderedComponent @ react.js:6312ReactCompositeComponentMixin._performComponentUpdate @ react.js:6287ReactCompositeComponentMixin.updateComponent @ react.js:6216wrapper @ react.js:12868ReactCompositeComponentMixin.performUpdateIfNecessary @ react.js:6164ReactReconciler.performUpdateIfNecessary @ react.js:13667runBatchedUpdates@react.js:15356Mixin.perform@ react.js:17245Mixin.perform@react.js:17245assign.perform@ react.js:15313flushBatchedUpdates @ react.js:15374wrapper @ react.js:12868Mixin.closeAll@react.js:17311Mixin.perform@ react.js:17258ReactDefaultBatchingStrategy.batchedUpdates @ react.js:8842batchedUpdates @ react.js:15321ReactEventListener.dispatchEvent@react.js:10336

第一个组件:

/** @jsx React.DOM */

var Second = require('components/second/view.jsx');

module.exports = React.createClass({

handlerClick: function () {
    ReactDOM.render(
        <Second />,
        document.getElementById("app-container")
    )
},

render: function() {
  return (
    <input type="button" value="COMPONENT 1" onClick={this.handlerClick} />
  )
}
});

第二个组件:

/** @jsx React.DOM */

var First = require('components/first/view.jsx');

module.exports = React.createClass({

handlerClick: function () {
    ReactDOM.render(
        <First />,
        document.getElementById("app-container")
    )
},

render: function() {
  return (
    <input type="button" value="COMPONENT 2" onClick={this.handlerClick} />
  )
}
});

索引.js

ReactDOM.render(
    <div>
        <First />
    </div>,
    document.getElementById("app-container")
);

【问题讨论】:

  • 无需添加整个错误消息,您也可以将问题清理得更具体,否则没有人可以提供帮助。

标签: javascript node.js reactjs components browserify


【解决方案1】:

您只在挂载应用程序时调用ReactDOM.render()。挂载后,您再也不会在同一个挂载点上调用ReactDOM.render()。 [*见下面的更新。]

请记住,您的视图是您的道具和状态的函数。要更改您的视图,请触发状态更改。

我建议是这样的:

var Parent = React.createClass({

    getInitialState: function () {
        return {
            active: 'FIRST'
        };
    },

    handleClick: function () {
        var active = this.state.active;
        var newActive = active === 'FIRST' ? 'SECOND' : 'FIRST';
        this.setState({
            active: newActive
        });
    },

    render: function () {

        var active = this.state.active;

        return (
            <div>
                {active === 'FIRST' ? (
                    <First />
                ) : active === 'SECOND' ? (
                    <Second />
                ) : null}
                <button type="button" onClick={this.handleClick}>
                    Toggle
                </button>
            </div>
        );

     }

});

并使 Parent 成为根节点。即

ReactDOM.render(<Parent />, document.getElementById('app-container'));

更新:我知道你可以致电ReactDOM.render()multiple times on the same mount point。这通常与您初始化应用程序的位置相同。不过,您当然不会从 React 组件内部调用 ReactDOM.render()

【讨论】:

    【解决方案2】:

    这是一个创建SwitchComponents 组件的非常简单的解决方案:

    // SwitchComponents.js:
    
    import React from 'react';
    
    export default function SwitchComponents({ active, children }) {
      // Switch all children and return the "active" one
      return children.filter(child => child.props.name == active)
    }
    

    并将其导入您的应用中:

    // App.js
    import SwitchComponents from './components/SwitchComponents';
    
    export default function App() {
    
    const [activeComponent, setActiveComponent] = useState("questions")
    
    return (
        <SwitchComponents active={activeComponent}>
          <Home name="home" />
          <Instructions name="instructions" />
          <FileboxContainer name="filebox" />
          <Questions name="questions" />
        </SwitchComponents>
      )
    }
    

    【讨论】:

    • 太棒了:)我从没想过过滤儿童道具
    【解决方案3】:

    Hooks 版本(React 16.8+):

    最小版本。

    import React, { useState } from 'react';
    
    export default function App() {
      const [toggle, setToggle] = useState(true);
      const toggleChecked = () => setToggle(toggle => !toggle);
      return (
         <div>
            {toggle && <First /> }
            {!toggle && <Second /> }
            <button type="button" onClick={this.toggleChecked}>
               Toggle
            </button>
         </div>
      );
    }
    

    【讨论】:

      【解决方案4】:

      在渲染函数中,三元运算符将被简单地替换,完整的答案如下:

          /** @jsx React.DOM */
      
          var Parent = React.createClass({
          getInitialState: function () {
              return {
                  active: 'FIRST'
              };
          },
      
              handleClick: function () {
                  var active = this.state.active;
                  var newActive = active === 'FIRST' ? 'SECOND' : 'FIRST';
                  this.setState({
                      active: newActive
                  });
              },
      
              render: function () {
      
                  var active = this.state.active;
      
                  return (
                      <div>
                          {(active === 'FIRST') && <First /> }
                          {(active === 'SECOND') && <Second /> }
                          <button type="button" onClick={this.handleClick}>
                              Toggle
                          </button>
                      </div>
                  );
      
               }
          });
      
      
        ReactDOM.render(<Parent />, document.getElementById('app-container'));
      

      其余的都是一样的。

      【讨论】:

        猜你喜欢
        • 2019-12-07
        • 2018-02-21
        • 1970-01-01
        • 2020-09-20
        • 1970-01-01
        • 1970-01-01
        • 2011-03-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多