【问题标题】:React App - render() - map () - mapping with if-else conditionReact App - render() - map () - 使用 if-else 条件映射
【发布时间】:2020-11-11 11:58:16
【问题描述】:

我创建了我的 ReactApp,并希望显示一个包含来自 AWS dynamodb 的数据的表格。

我成功的将dynamodb中的数据通过json传输到ReactApp,通过ReactApp的render()中的map(),我显示的表格如下:

How it looks now

所以现在我需要将表格重新分配如下:

How i want it to display

所以我计划相应地使用 if-else 语句来呈现表格: 但是一旦我在函数中添加了 if-else 子句,它就不起作用并且什么也没有显示。所以想向stackoverflow专家寻求建议:)非常感谢提前

这是我的代码,我卡住的部分在 render() 的返回部分:

class App extends Component {
  constructor(props) {
    super(props);

    this.state = {
      hits: [],
      isLoading: false,
      error: null,
    };
  }

  render() {
    const { hits, isLoading, error } = this.state;

    if (error) {
      return <p>{error.message}</p>;
    }

    if (isLoading) {
      return <p>Loading ...</p>;
    }

    return (
      <form>
        <div className="container border border-secondary rounded center">
          <div className="row">
            <div className="col-12">
              {' '}
              <h4>
                <b>Class Mapping</b>
              </h4>{' '}
            </div>
          </div>

          <div className=".col-xs-12 center text-center">
            <Table responsive striped bordered hover>
              <tr>
                <th>Class 1</th>
                <th>Class 2</th>
                <th>Class 3</th>
                <th>Class 4</th>
                <th>Class 5</th>
              </tr>

              <tbody>
                {hits.map((hit) => {
                  if (hit.class === 'Class 1') {
                    <tr>
                      <td>{hit.name}}</td> <td></td> <td></td> <td></td> <td></td>{' '}
                    </tr>;
                  } else if (hit.class === 'Class 2') {
                    <tr>
                      <td></td>
                      <td>{hit.name}}</td> <td></td> <td></td> <td></td>{' '}
                    </tr>;
                  }
                })}
              </tbody>
            </Table>
          </div>
        </div>
      </form>
    );
  }

  async componentDidMount() {
    this.setState({ isLoading: true });
    const response = await fetch('https://xxxxxxx');
    const body = await response.json();
    this.setState({ hits: body, isLoading: false, error: null });
  }
}
export default App;

【问题讨论】:

    标签: reactjs dictionary jsx


    【解决方案1】:

    所以你想要一个看起来像这样的数组:

    const hits = [
      { name: 'Tammy', class: 'Class 1' },
      { name: 'Sarah', class: 'Class 2' },
      { name: 'Roland', class: 'Class 3' },
      { name: 'Moshe', class: 'Class 4' },
      { name: 'Peter', class: 'Class 5' },
    ];
    

    并将其转换为名称数组,按其类名排列成列,如下所示:

    const rows = [
      ['Tammy', 'Sarah', 'Roland', 'Moshe', 'Peter'],
      ['Helen', 'Eric', 'Fiona', 'Darren', 'Andy'],
    ];
    

    这需要一些工作。我不认为你可以在几个 map 函数中使用 if/else 语句来完成它。

    让我们试试这个。我建议向您的组件添加一个名为 getRows 的类方法。此方法将进行转换。我们首先遍历您的 hits 并按类对名称进行分组。

    然后我们设置一个 while 循环,将名称推送到新的行数组中。虽然我们还有名字,但请继续构建行。每一行都会根据列选择一个名称并插入。

    最后,当我们都没有名字时,我们可以将行返回给渲染函数。然后我们映射行,并映射每行中的列。我们还需要每个映射元素的唯一键。

    getRows()

    const getRows = () => {
      const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
      const rows = [];
    
      const groupByColumn = this.state.hits.reduce((acc, next) => {
        return { ...acc, [next.class]: [...(acc[next.class] || []), next.name] };
      }, {});
    
      const haveNames = () => columns.some((column) => (groupByColumn[column] || []).length > 0);
    
      while (haveNames()) {
        const newRow = columns.map((column) => {
          return (groupByColumn[column] || []).shift() || '';
        });
    
        rows.push(newRow);
      }
    
      return rows;
    };
    

    完整的组件:

    import React, { Component } from 'react';
    
    class App extends Component {
      constructor(props) {
        super(props);
    
        this.state = {
          hits: [],
          isLoading: false,
          error: null,
        };
      }
    
      async componentDidMount() {
        this.setState({ isLoading: true });
        const response = await fetch('https://xxxxxxx');
        const body = await response.json();
        this.setState({ hits: body, isLoading: false, error: null });
      }
    
      getRows = () => {
        const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
        const rows = [];
      
        const groupByColumn = this.state.hits.reduce((acc, next) => {
          return { ...acc, [next.class]: [...(acc[next.class] || []), next.name] };
        }, {});
      
        const haveNames = () => columns.some((column) => (groupByColumn[column] || []).length > 0);
      
        while (haveNames()) {
          const newRow = columns.map((column) => {
            return (groupByColumn[column] || []).shift() || '';
          });
      
          rows.push(newRow);
        }
      
        return rows;
      };
    
      render() {
        if (this.state.error) {
          return <p>{error.message}</p>;
        }
    
        if (this.state.isLoading) {
          return <p>Loading ...</p>;
        }
    
        return (
          <form>
            <div className="container border border-secondary rounded center">
              <div className="row">
                <div className="col-12">
                  {' '}
                  <h4>
                    <b>Class Mapping</b>
                  </h4>{' '}
                </div>
              </div>
    
              <div className=".col-xs-12 center text-center">
                <Table responsive striped bordered hover>
                  <tr>
                    <th>Class 1</th>
                    <th>Class 2</th>
                    <th>Class 3</th>
                    <th>Class 4</th>
                    <th>Class 5</th>
                  </tr>
                  <tbody>
                    {this.getRows().map((row) => (
                      <tr key={row.reduce((a, b) => a + b)}>
                        {row.map((column) => (
                          <td key={column}>{column}</td>
                        ))}
                      </tr>
                    ))}
                  </tbody>
                </Table>
              </div>
            </div>
          </form>
        );
      }
    }
    
    export default App;
    

    示例代码

    const hits = [
      { name: 'Tammy', class: 'Class 1' },
      { name: 'Camen', class: 'Class 2' },
      { name: 'Happy', class: 'Class 3' },
      { name: 'Hello Kitty', class: 'Class 4' },
      { name: 'Hello Mimi', class: 'Class 3' },
    ];
    
    const getRows = (hits) => {
      const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
      const rows = [];
    
      const groupByColumn = hits.reduce((acc, next) => {
        return { ...acc, [next.class]: [...(acc[next.class] || []), next.name] };
      }, {});
    
      const haveNames = () => columns.some((column) => (groupByColumn[column] || []).length > 0);
    
      while (haveNames()) {
        const newRow = columns.map((column) => {
          return (groupByColumn[column] || []).shift() || '';
        });
    
        rows.push(newRow);
      }
    
      return rows;
    };
    
    const rows = getRows(hits);
    console.log(rows);

    【讨论】:

    • 嗨@Benjamin,非常感谢它鼓舞人心。你擅长内联表达式,我正在学习:) 我可以在 getRow() 上咨询更多信息,当我运行 groupByColumn() 时,它说“...acct [next.class]”没有定义。但我考虑使用扩展运算符和数组,即使它是空的,这些项目也会添加到数组中。请您指导我吗?我将完整的新代码放在便于参考。还在顶部添加了数组的默认设置,所以我们可以看到全图。非常感谢!github.com/farislui/react_table_remap/blob/main/App.js
    • @farislui 嗯,'...acc[next.class] 未定义'不应该发生。累加器acc 用一个空对象初始化,每次迭代总是返回一个新对象,所以不会发生 acc 未定义的情况。也许你有错字?尝试完全按照我编写的方式复制 getRows 函数。我注意到您共享的 git 存储库中有错字。在第 92 行 const haveNames 你错过了groupByColumn[column].length
    • @farislui 好的,我在代码中看到了错误。我看到您的样本命中只有 1-4 类。我的代码包括第 5 类。如果该类不存在,我已经在几个地方更新了代码以安全地回退到空数组|| []。您可以使用您的实际列更新const columns = ['Class 1', 'Class 2', 'Class 3', 'Class 4', 'Class 5'];
    • 嗨@Benjamin,非常感谢你,现在我明白了,你太棒了,代码正在运行。谢谢你的建议,我真的学到了很多
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-09
    • 2019-09-11
    • 1970-01-01
    • 1970-01-01
    • 2019-04-25
    • 1970-01-01
    相关资源
    最近更新 更多