迭代通过数组需要方向

时间:2017-09-15 02:32:35

标签: javascript reactjs

请原谅我的无知。我刚开始使用反应,我相信我在这里错过了一些非常简单的东西。因此,根据我从loadData返回的数据量,我需要在1 2或3列中显示数据。我正在使用ul和li。我根据屏幕大小计算出可以容纳多少列。我尝试将它们全部放在一个ul中,但我需要在顶部有一个标题行,所以我真的需要最多3 uls,第一个li有头信息。我如何循环并创建我需要的数量?我尝试围绕回归做了一个循环,但我无法做到。非常感谢任何帮助。

    var appointmentBoardSection = React.createClass({
    displayName: "appointmentBoardSection",
    getInitialState: function() {
        return {
            key: null,
            results: [],
            parameters: this.props.parameters,
            type: "",
        };
    },

    shouldComponentUpdate: function(nextProps, nextState) {

        console.info("this.state.key: " + this.state.key);
        console.info("nextState.key: " + nextState.key);

        if (this.state.key !== nextState.key) {
            console.info("NO MATCH!!!!");
            //this.forceUpdate();
            return true;
        }

        return false;
    },

    componentDidMount: function() {
        console.info("MOUNTED!!!");
        var _this = this;
        _this.loadData();
        setInterval(function() {
            _this.loadData();
        }, 10000);
    },

    loadData: function() {

        console.info("LOADING DATA....");
        var _this = this;

        $.when(_api.callPromise('apiRouter.ashx', 'getAppointmentsBoard', JSON.stringify(masterPage.reporting.parameters), this.props.type)).then(function(data) {
            var totalData = data.args[0];

            if (totalData.length <= 0) {
                $("div#" + _this.props.type).hide();
            } else {
                $("#no_data").hide();
                $("div#" + _this.props.type).show();
            }

            _this.setState({
                results: totalData,
                key: Math.random()
            });
            masterPage.hidePleaseWait(true);
        });
    },

    render: function() {

        var contHeight = $(window).height();
        var offsetTop = $("div.appt_bd_container").offset().top;
        var realEstate = contHeight - 400;
        var perColumn = Math.round(realEstate / 70);

        console.info("height: " + $(window).height());
        console.info("offsetTop: " + offsetTop);
        console.info("perColumn: " + perColumn);

        var maxICanShow = perColumn * 3;
        var limitResults = false;
        var colCount = 3;

        var colDef = "";
        var colWidth = 100;

        var numberOfColsNeeded = Math.round(this.state.results.length / perColumn);

        if (numberOfColsNeeded > 3) {
            colCount = 3;
        } else {
            colCount = numberOfColsNeeded;
        }

        switch (colCount) {
            case 2:
                colWidth = 50;
                break;
            case 3:
                colWidth = 33.333;
                break;
            default:
                colDef = "";
                colWidth = 100;
        }

        if (this.state.results.length > maxICanShow) {
            var i = 1;
            console.info("this.state.results.length: " + this.state.results.length);
            console.info("maxICanShow: " + maxICanShow);
            while (i < this.state.results.length - (maxICanShow - 1)) {
                this.state.results.pop();
                i++;
            }
        }


        var curColData = [];
        var overallCount = this.state.results.length;

        var testArr = [];

        for (var i = 0; i < colCount; i++) {
            testArr.push({});
        }

        if (this.state.results.length > perColumn) {
            for (var i = 0; i < perColumn; i++) {
                if (overallCount > 0) {
                    curColData.push(this.state.results.shift());
                    overallCount--;
                }
            }
        }

        var myTest = [];

        return ( <
            ul className = "appt_bd" >
            <
            li className = "appt_bd_header"
            style = {
                {
                    width: colWidth + '%'
                }
            } >
            <
            span className = "appt_bd_header_main" > {
                this.props.title
            } < /span> <
            span className = "appt_bd_header_sub" > Appts Set < /span> <
            span className = "appt_bd_header_sub" > Appts Show < /span> <
            /li> {
                curColData.map(function(row) {
                    return <AppointmentBoardRow colWidth = {
                        colWidth
                    }
                    key = {
                        row.userId
                    }
                    row = {
                        row
                    }
                    />;
                })
            } <
            /ul>
        );
    }
});

var AppointmentBoardRow = React.createClass({
    render: function() {
        var row = this.props.row;
        return ( <
            li className = "appt_bd_row"
            style = {
                {
                    width: this.props.colWidth + '%'
                }
            }
            key = {
                row.userId
            } >
            <
            span className = "appt_bd_desc" >
            <
            span className = "appt_bd_rank" > {
                row.rank
            } < /span> <
            span className = "appt_bd_avatar_container" > < div className = {
                row.className
            } > < span className = "initials" > {
                row.initials
            } < /span></div > < /span> <
            span className = "appt_bd_user" >
            <
            span className = "appt_bd_description_main" > {
                row.userName
            } < /span> <
            span className = "appt_bd_description_sub" > {
                row.role
            } < /span> <
            /span> <
            /span> <
            span className = "appt_bd_data" >
            <
            span className = "appt_bd_data_main" > {
                row.apptsSetCount
            } < /span> <
            span className = "appt_bd_data_sub" > /{row.apptsSetGoal}</span >
            <
            /span> <
            span className = "appt_bd_data" >
            <
            span className = "appt_bd_data_main" > {
                row.apptsShowCount
            } < /span> <
            span className = "appt_bd_data_sub" > /{row.apptsShowGoal}</span >
            <
            /span> <
            /li>
        );
    }
});

****编辑回应Josh ...我现在遇到的一个问题是什么都没有显示虽然我可以验证uls是否正确。这是我的渲染:

render: function () {

    var contHeight = $(window).height();
    var offsetTop = $("div.appt_bd_container").offset().top;
    var realEstate = contHeight - 400;
    var perColumn = Math.round(realEstate / 70);
    var maxICanShow = perColumn * 3;
    var colWidth = 100;

    var uls = _.chunk(_.take(this.state.results, maxICanShow), perColumn);
    let li = "";

    return (
        <div>
        {uls.map((lis) => {
            <ul className="appt_bd">
                <li className="appt_bd_header" style={{ width: colWidth + '%' }}>
                    <span className="appt_bd_header_main">{this.props.title}</span>
                    <span className="appt_bd_header_sub">Appts Set</span>
                    <span className="appt_bd_header_sub">Appts Show</span>
                </li>
                lis.map(li => {<li className="appt_bd_row" style={{ width: this.props.colWidth + '%' }} key={li.userId}>
                    <span className="appt_bd_desc">
                        <span className="appt_bd_rank">{li.rank}</span>
                        <span className="appt_bd_avatar_container"><div className={li.className}><span className="initials">{li.initials}</span></div></span>
                        <span className="appt_bd_user">
                            <span className="appt_bd_description_main">{li.userName}</span>
                            <span className="appt_bd_description_sub">{li.role}</span>
                        </span>
                    </span>
                    <span className="appt_bd_data">
                        <span className="appt_bd_data_main">{li.apptsSetCount}</span>
                        <span className="appt_bd_data_sub">/{li.apptsSetGoal}</span>
                    </span>
                    <span className="appt_bd_data">
                        <span className="appt_bd_data_main">{li.apptsShowCount}</span>
                        <span className="appt_bd_data_sub">/{li.apptsShowGoal}</span>
                    </span>
                </li>})
            </ul>
        })}
            </div>
    );
}

1 个答案:

答案 0 :(得分:2)

通过使用lodash,您可以简化构建布局的算法。请参阅下文,了解render

的开头部分
    render: function() {

      var contHeight = $(window).height();
      var offsetTop = $("div.appt_bd_container").offset().top;
      var realEstate = contHeight - 400;
      var perColumn = Math.round(realEstate / 70);
      var maxICanShow = perColumn * 3;

      var uls = _.chunk(_.take(this.state.results, maxICanShow), perColumn);
switch (uls.length) {
    case 2:
        colWidth = 50;
        break;
    case 3:
        colWidth = 33.333;
        break;
    default:
        colDef = "";
        colWidth = 100;
}

在此之后,您不需要您编写的任何其他代码,直到     return {... 但您需要将模板映射到uls而不是curColData。它看起来像这样(过于简化):

uls.map((lis) => {
  <ul>
    <li> my header </li>
    lis.map(li => <li></li>)
  </ul>
})

值得注意的是,我的解决方案在return视图中使用了双重迭代,在可能的情况下应该避免 - 特别是在可能很大的集合中;但由于你的集合不会(给定容器的大小)并且你想动态构建嵌套元素,它似乎是需求的正确模式。

现在uls将是一个数组数组,用于将数据映射到您建议的视图结构。具体来说,您的ul将由uls中的每个数组表示;那么,嵌套数组中的每个项目都代表li。 将uls[0]作为您的第一个ululs[0][0]将成为您第一个li的第一个ul

可以找到

_.take文档here

可以找到

_.chunk文档here

希望将您的数据转换为与所需视图类似的结构将有助于您前进。

我还要说代码中还有许多其他问题。例如,React人员可能会告诉你混合jQuery是一个禁忌。

更新9/15/17 我想到了更多,并意识到没有双重迭代有更冗长的方式。您只需要三列,我们可以使用它来映射三个单独的ul元素,这些元素都包含要显示的总项目的块。如果该块恰好不存在(项目数量少于max this.state.results.length < maxICanShow),那么由于方便的花花公子lodash,它不会成为问题。请参阅以下代码:

class ListPane extends React.Component {          
  render () {

    var contHeight = 900;//$(window).height();
    var offsetTop = 50; //$("div.appt_bd_container").offset().top;
    var realEstate = contHeight - 400;
    var perColumn = Math.round(realEstate / 70);
    var maxICanShow = perColumn * 3;
    var uls = "abcedefhijklmnopqrstuvwxyz".split("");
    var chunks = _.chunk(_.take(uls, maxICanShow), perColumn);
    var colWidth = 0;
    var colA = _.map(_.nth(chunks, 0), item => <li>{item}</li>)
    var colB = _.map(_.nth(chunks, 1), item => <li>{item}</li>)
    var colC = _.map(_.nth(chunks, 2), item => <li>{item}</li>)
    const listItems = chunks.map((lis) =>
        <ul>
          <li> {lis} </li>
        </ul>
    );

    switch (chunks.length) {
      case 2:
        colWidth = 50;
        break;
      case 3:
        colWidth = 33.333;
        break;
      default:
        colWidth = 100;
    }

    return (
      <div>
        <ul>
          {colA}
        </ul>
        <ul>
          {colB}
        </ul>
        <ul>
          {colC}
        </ul>
      </div>
    )
  }
}         

注意我使用_.nth来保护代码免受潜在的null或不可解析的引用。

另外,请查看此codepen

还可以进行其他改进。

  1. 而不是 var colC = _.map(_.nth(chunks, 2), item => <li>{item}</li>), 在ListItem替代创建另一个类可能更加清晰,可能li。 所以, var colC = _.map(_.nth(chunks, 2), item => <ListItem data={item} />)
  2. 奇怪的是,我注意到列表项的部分列从上到下流动。因此,如果您'abcedfghijkl'.split(''),您将获得两列,第二组li位于底部。我不是很确定为什么,但不觉得它从演示中消失了。
  3. 关于React的最终说明,以及为什么我不会/不会使用它。它的许可证并非真正开放,许多人都对此感到担忧。如果您刚刚进入React,可能是选择其他东西的好时机。见this reddit