【问题标题】:JSX expressions must have one parent elementJSX 表达式必须有一个父元素
【发布时间】:2020-03-09 12:01:28
【问题描述】:

我在编辑器中的following code 工作正常。

import React, { Component } from "react";
import { render } from "react-dom";
import "jqwidgets-scripts/jqwidgets/styles/jqx.base.css";
import JqxButton from "jqwidgets-scripts/jqwidgets-react-tsx/jqxbuttons";
import * as ReactDOM from "react-dom";
import JqxWindow from "jqwidgets-scripts/jqwidgets-react-tsx/jqxwindow";
import JqxInput from "jqwidgets-scripts/jqwidgets-react-tsx/jqxinput";

import JqxChart, {
  IChartProps
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxchart";
import JqxGrid, {
  IGridProps,
  jqx
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxgrid";
import JqxTabs from "jqwidgets-scripts/jqwidgets-react-tsx/jqxtabs";
import JqxDropDownList, {
  IDropDownListProps
} from "jqwidgets-scripts/jqwidgets-react-tsx/jqxdropdownlist";

interface AppProps {}
interface AppState {
  name: string;
}
interface IProps extends IGridProps {
  rendertoolbar1: IGridProps["rendertoolbar"];
  dropdownlistSource: IDropDownListProps["source"];
}

class App extends Component<{}, IProps> {
  private myTabs = React.createRef<JqxTabs>();
  private gridElement = React.createRef<HTMLDivElement>();
  private gridElementTwo = React.createRef<HTMLDivElement>();
  private myGrid = React.createRef<JqxGrid>();
  private myGrid2 = React.createRef<JqxGrid>();
  private myWindow = React.createRef<JqxWindow>();
  private myWindowTWO = React.createRef<JqxWindow>();
  private date = React.createRef<JqxInput>();
  private sAndP500 = React.createRef<JqxInput>();

  constructor(props: {}) {
    super(props);
    this.saveBtn = this.saveBtn.bind(this);
    this.cancelBtn = this.cancelBtn.bind(this);
    this.saveBtntwo = this.saveBtn.bind(this);
    this.cancelBtntwo = this.cancelBtn.bind(this);

    const rendertoolbar = (toolbar: any): void => {
      const addRowClick = () => {
        //const datarow = this.generaterow();
        //this.myGrid.current!.addrow(null, datarow);
        this.myWindow.current!.open();
      };

      const addRowClickTwo = () => {
        //const datarow = this.generaterow();
        //this.myGrid.current!.addrow(null, datarow);
        this.myWindowTWO.current!.open();
      };

      ReactDOM.render(
        <div style={{ margin: "5px" }}>
          <div
            id="buttonContainer2"
            style={{ float: "left", marginLeft: "5px" }}
          >
            <JqxButton
              onClick={addRowClickTwo}
              width={125}
              value={"Add New NASDAQ"}
            />
          </div>
        </div>,
        toolbar[0]
      );
    };

    const rendertoolbar1 = (toolbar: any): void => {
      const addRowClick = () => {
        //const datarow = this.generaterow();
        //this.myGrid.current!.addrow(null, datarow);
        this.myWindow.current!.open();
      };

      const addRowClickTwo = () => {
        //const datarow = this.generaterow();
        //this.myGrid.current!.addrow(null, datarow);
        this.myWindowTWO.current!.open();
      };

      ReactDOM.render(
        <div style={{ margin: "5px" }}>
          <div id="buttonContainer1" style={{ float: "left" }}>
            <JqxButton
              onClick={addRowClick}
              width={135}
              value={"Add New Us Index"}
            />
          </div>
        </div>,
        toolbar[0]
      );
    };

    this.state = {
      rendertoolbar,
      rendertoolbar1,
      // dropdownlistSource: ["Affogato", "Americano", "Bicerin", "Breve"]
      dropdownlistSource: [
        { value: 0, label: "Affogato" },
        { value: 1, label: "Americano" },
        { value: 2, label: "Bicerin" },
        { value: 3, label: "Breve" }
      ]
      //source: new jqx.dataAdapter(source)
    };
  }
  public render() {
    return (
      <JqxTabs
        ref={this.myTabs}
        // @ts-ignore
        width={400}
        height={560}
        initTabContent={this.initWidgets}
        onSelected={this.onTabSelected}
      >
        <JqxWindow
          ref={this.myWindow}
          width={250}
          height={230}
          resizable={false}
          isModal={false}
          autoOpen={false}
          modalOpacity={"0.01"}
          position={{ x: 68, y: 368 }}
        >
          <div>Add New US Indexes</div>
          <div style={{ overflow: "hidden" }}>
            <table>
              <tbody>
                <tr>
                  <td align={"right"}>Date:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.date} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"}>S & P 500:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.sAndP500} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"}>DropDownList:</td>
                  <td align={"left"}>
                    <JqxDropDownList
                      width={100}
                      height={20}
                      source={this.state.dropdownlistSource}
                      selectedIndex={0}
                    />
                  </td>
                </tr>
                <tr>
                  <td align={"right"} />
                  <td style={{ paddingTop: "10px" }} align={"right"}>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.saveBtn}
                      width={50}
                    >
                      Save
                    </JqxButton>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.cancelBtn}
                      width={50}
                    >
                      Cancel
                    </JqxButton>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </JqxWindow>
        <JqxWindow
          ref={this.myWindowTWO}
          width={250}
          height={230}
          resizable={false}
          isModal={false}
          autoOpen={false}
          modalOpacity={"0.01"}
          position={{ x: 68, y: 368 }}
        >
          <div>Add New NASDAQ</div>
          <div style={{ overflow: "hidden" }}>
            <table>
              <tbody>
                <tr>
                  <td align={"right"}>Date:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.date} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"}>S & P 500:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.sAndP500} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"} />
                  <td style={{ paddingTop: "10px" }} align={"right"}>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.saveBtntwo}
                      width={50}
                    >
                      Save
                    </JqxButton>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.cancelBtntwo}
                      width={50}
                    >
                      Cancel
                    </JqxButton>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </JqxWindow>
        <ul>
          <li style={{ marginLeft: 30 }}>
            <div style={{ height: 20, marginTop: 5 }}>
              <div style={{ float: "left" }}>
                <img width="16" height="16" src="./../images/catalogicon.png" />
              </div>
              <div
                style={{
                  marginLeft: 4,
                  verticalAlign: "middle",
                  textAlign: "center",
                  float: "left"
                }}
              >
                US Indexes
              </div>
            </div>
          </li>
          <li>
            <div style={{ height: 20, marginTop: 5 }}>
              <div style={{ float: "left" }}>
                <img width="16" height="16" src="./../images/pieicon.png" />
              </div>
              <div
                style={{
                  marginLeft: 4,
                  verticalAlign: "middle",
                  textAlign: "center",
                  float: "left"
                }}
              >
                NASDAQ compared to S&P 500
              </div>
            </div>
          </li>
        </ul>
        <div style={{ overflow: "hidden" }}>
          <div id="jqxGrid" ref={this.gridElement} />
          <div style={{ marginTop: 10, height: "15%" }} />
        </div>
        <div style={{ overflow: "hidden" }}>
          <div id="jqxGrid2" ref={this.gridElementTwo} />
          <div style={{ marginTop: 10, height: "15%" }} />
        </div>
      </JqxTabs>
    );
  }
  private initGrid = () => {
    const source = {
      datafields: [{ name: "Date" }, { name: "S&P 500" }, { name: "NASDAQ" }],
      datatype: "csv",
      //url: './assets/nasdaq_vs_sp500.txt'
      localdata: `1/2/2014,1831.98,4143.07
1/3/2014,1831.37,4131.91
1/6/2014,1826.77,4113.68
1/7/2014,1837.88,4153.18
1/8/2014,1837.49,4165.61
1/9/2014,1838.13,4156.19
1/10/2014,1842.37,4174.67
1/13/2014,1819.2,4113.3
1/14/2014,1838.88,4183.02
1/15/2014,1848.38,4214.88
1/16/2014,1845.89,4218.69
1/17/2014,1838.7,4197.58
1/21/2014,1843.8,4225.76
1/22/2014,1844.86,4243
1/23/2014,1828.46,4218.88
1/24/2014,1790.29,4128.17
1/27/2014,1781.56,4083.61
1/28/2014,1792.5,4097.96
1/29/2014,1774.2,4051.43
1/30/2014,1794.19,4123.13
1/31/2014,1782.59,4103.88
2/3/2014,1741.89,3996.96
2/4/2014,1755.2,4031.52
2/5/2014,1751.64,4011.55
2/6/2014,1773.43,4057.12
2/7/2014,1797.02,4125.86`
    };

    const dataAdapter = new jqx.dataAdapter(source, {
      async: false,
      loadError: (xhr: any, status: any, error: any) => {
        console.log(xhr, status, error);
        //alert('Error loading "' + source.url + '" : ' + error);
      }
    });

    const columns: IGridProps["columns"] = [
      { cellsformat: "d", datafield: "Date", text: "Date", width: 250 },
      { datafield: "S&P 500", text: "S&P 500", width: 150 },
      { datafield: "NASDAQ", text: "NASDAQ" }
    ];
    const grid = (
      <JqxGrid
        ref={this.myGrid}
        width={"100%"}
        height={400}
        source={dataAdapter}
        columns={columns}
        showtoolbar={true}
        rendertoolbar={this.state.rendertoolbar1}
      />
    );
    render(grid, this.gridElement.current!);
  };
  private saveBtn(): void {
    this.myWindow.current!.hide();
  }

  private cancelBtn(): void {
    this.myWindow.current!.hide();
  }

  private initGrid2 = () => {
    const source = {
      datafields: [{ name: "Date" }, { name: "S&P 500" }, { name: "NASDAQ" }],
      datatype: "csv",
      //url: './assets/nasdaq_vs_sp500.txt'
      localdata: `1/2/2014,1831.98,4143.07
1/3/2014,1831.37,4131.91
1/6/2014,1826.77,4113.68
1/7/2014,1837.88,4153.18
1/8/2014,1837.49,4165.61
1/9/2014,1838.13,4156.19
1/10/2014,1842.37,4174.67
1/13/2014,1819.2,4113.3
1/14/2014,1838.88,4183.02
1/15/2014,1848.38,4214.88
1/16/2014,1845.89,4218.69
1/17/2014,1838.7,4197.58
1/21/2014,1843.8,4225.76
1/22/2014,1844.86,4243
1/23/2014,1828.46,4218.88
1/24/2014,1790.29,4128.17
1/27/2014,1781.56,4083.61
1/28/2014,1792.5,4097.96
1/29/2014,1774.2,4051.43
1/30/2014,1794.19,4123.13
1/31/2014,1782.59,4103.88
2/3/2014,1741.89,3996.96
2/4/2014,1755.2,4031.52
2/5/2014,1751.64,4011.55
2/6/2014,1773.43,4057.12
2/7/2014,1797.02,4125.86`
    };

    const dataAdapter = new jqx.dataAdapter(source, {
      async: false,
      loadError: (xhr: any, status: any, error: any) => {
        console.log(xhr, status, error);
        //alert('Error loading "' + source.url + '" : ' + error);
      }
    });

    const columns: IGridProps["columns"] = [
      { cellsformat: "d", datafield: "Date", text: "Date", width: 250 },
      { datafield: "S&P 500", text: "S&P 500", width: 150 },
      { datafield: "NASDAQ", text: "NASDAQ" }
    ];
    const grid = (
      <JqxGrid
        ref={this.myGrid2}
        width={"100%"}
        height={400}
        source={dataAdapter}
        columns={columns}
        showtoolbar={true}
        rendertoolbar={this.state.rendertoolbar}
      />
    );
    render(grid, this.gridElementTwo.current!);
  };

  private saveBtntwo(): void {
    this.myWindowTWO.current!.hide();
  }

  private cancelBtntwo(): void {
    this.myWindowTWO.current!.hide();
  }

  private initWidgets = (tab: any) => {
    switch (tab) {
      case 0:
        this.initGrid();
        break;
      case 1:
        this.initGrid2();
        break;
    }
  };

  private onTabSelected = (event: any) => {
    switch (event.args.item) {
      case 0:
        // this.hideButton();
        break;
      case 1:
        //  this.showButton();
        break;
    }
  };
}

render(<App />, document.getElementById("root"));

我试图不将 &lt;JqxWindow&gt;&lt;/JqxWindow&gt; 嵌套在 &lt;JqxTabs&gt;&lt;/JqxTabs&gt; 中,因为根据 jQXWidgets 团队的说法,这对于 React 应用程序的正常运行来说不是一个好主意。

所以,我用div 标签包围了一个&lt;JqxTabs&gt;&lt;/JqxTabs&gt;,用两个divs 包围了两个&lt;JqxWindow&gt;&lt;/JqxWindow&gt;,如下面的代码和editor here 所示:

 public render() {
    return (
      <div>
      <JqxTabs
        ref={this.myTabs}
        // @ts-ignore
        width={400}
        height={560}
        initTabContent={this.initWidgets}
        onSelected={this.onTabSelected}
      >

        <ul>
          <li style={{ marginLeft: 30 }}>
            <div style={{ height: 20, marginTop: 5 }}>
              <div style={{ float: "left" }}>
                <img width="16" height="16" src="./../images/catalogicon.png" />
              </div>
              <div
                style={{
                  marginLeft: 4,
                  verticalAlign: "middle",
                  textAlign: "center",
                  float: "left"
                }}
              >
                US Indexes
              </div>
            </div>
          </li>
          <li>
            <div style={{ height: 20, marginTop: 5 }}>
              <div style={{ float: "left" }}>
                <img width="16" height="16" src="./../images/pieicon.png" />
              </div>
              <div
                style={{
                  marginLeft: 4,
                  verticalAlign: "middle",
                  textAlign: "center",
                  float: "left"
                }}
              >
                NASDAQ compared to S&P 500
              </div>
            </div>
          </li>
        </ul>
        <div style={{ overflow: "hidden" }}>
          <div id="jqxGrid" ref={this.gridElement} />
          <div style={{ marginTop: 10, height: "15%" }} />
        </div>
        <div style={{ overflow: "hidden" }}>
          <div id="jqxGrid2" ref={this.gridElementTwo} />
          <div style={{ marginTop: 10, height: "15%" }} />
        </div>
      </JqxTabs>
      </div>
      <div>
       <JqxWindow
          ref={this.myWindow}
          width={250}
          height={230}
          resizable={false}
          isModal={false}
          autoOpen={false}
          modalOpacity={"0.01"}
          position={{ x: 68, y: 368 }}
        >
          <div>Add New US Indexes</div>
          <div style={{ overflow: "hidden" }}>
            <table>
              <tbody>
                <tr>
                  <td align={"right"}>Date:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.date} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"}>S & P 500:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.sAndP500} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"}>DropDownList:</td>
                  <td align={"left"}>
                    <JqxDropDownList
                      width={100}
                      height={20}
                      source={this.state.dropdownlistSource}
                      selectedIndex={0}
                    />
                  </td>
                </tr>
                <tr>
                  <td align={"right"} />
                  <td style={{ paddingTop: "10px" }} align={"right"}>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.saveBtn}
                      width={50}
                    >
                      Save
                    </JqxButton>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.cancelBtn}
                      width={50}
                    >
                      Cancel
                    </JqxButton>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </JqxWindow>
        </div>
        <div>
        <JqxWindow
          ref={this.myWindowTWO}
          width={250}
          height={230}
          resizable={false}
          isModal={false}
          autoOpen={false}
          modalOpacity={"0.01"}
          position={{ x: 68, y: 368 }}
        >
          <div>Add New NASDAQ</div>
          <div style={{ overflow: "hidden" }}>
            <table>
              <tbody>
                <tr>
                  <td align={"right"}>Date:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.date} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"}>S & P 500:</td>
                  <td align={"left"}>
                    <JqxInput ref={this.sAndP500} width={150} height={23} />
                  </td>
                </tr>
                <tr>
                  <td align={"right"} />
                  <td style={{ paddingTop: "10px" }} align={"right"}>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.saveBtntwo}
                      width={50}
                    >
                      Save
                    </JqxButton>
                    <JqxButton
                      style={{ display: "inline-block", marginRight: "5px" }}
                      onClick={this.cancelBtntwo}
                      width={50}
                    >
                      Cancel
                    </JqxButton>
                  </td>
                </tr>
              </tbody>
            </table>
          </div>
        </JqxWindow>
        </div>
    );
  }

它一直在抱怨以下问题:

我没有正确使用divs吗?

我应该用片段而不是 div 包围所有内容,如下所示: How to fix JSX expression must have one parent element?

【问题讨论】:

  • 是否应该将其包装成&lt;div&gt;&lt;Fragment&gt; 取决于您是否希望容器在DOM 中表示。如果您使用&lt;div&gt;,则可以为其指定一个类或ID。如果不需要,可以使用片段。
  • 此外,如果您使用好的代码编辑器,您可以通过代码突出显示或折叠部分树(如果缺少结束标记)轻松查看。你的组件也很大,应该拆分成更小的组件。
  • 这能回答你的问题吗? React - expressions must have one parent element?

标签: reactjs jsx


【解决方案1】:

请用父容器包装所有元素。请确保您正在渲染一个实体。

即:

<div> // parent container
    <JqxTabs/>
    <JqxWindow />
</div>

你也可以使用 Fragment 元素作为父元素。

import React, {Fragment} from 'react';

【讨论】:

  • 我在我的代码中这样做了,代码没有抛出任何错误,但我的功能没有按预期工作。
  • 是的。所以问题得到了解决。以防万一,您需要再次检查您的功能。
  • "JSX 表达式必须有一个父元素"。这是您在没有父容器的情况下呈现多实体的相关问题。
【解决方案2】:

你只能从一个 react 组件返回一个元素。用另一个&lt;div&gt; 或一个反应片段&lt;React.Fragment&gt; (或&lt;&gt;...&lt;/&gt; 的简写)包装你的渲染中的所有内容。 See docs on fragments

可以接受 div 或片段,但问题是您要返回多个元素,而不仅仅是一个。

【讨论】:

    【解决方案3】:

    您将需要从反应组件返回单个元素。为此,您可以尝试其中一种方法。

    使用片段

    import React, { Component,Fragment } from "react";
    
    <Fragment> 
        <JqxTabs/>
        <JqxWindow />
    </Fragment>
    

    <> 
        <JqxTabs/>
        <JqxWindow />
    </>
    

    或者你可以用 div 包裹每个元素

    <div> 
        <JqxTabs/>
        <JqxWindow />
    </div>
    

    【讨论】:

      猜你喜欢
      • 2020-07-30
      • 1970-01-01
      • 2022-01-05
      • 1970-01-01
      • 2023-02-13
      • 2020-04-24
      • 1970-01-01
      • 2021-11-09
      相关资源
      最近更新 更多