Свойство React представляет собой пустой объект вместо намеченного массива - PullRequest
0 голосов
/ 15 января 2020

Я пытаюсь реализовать GroupedList из управляющей библиотеки Office UI Fabir c, и я не слишком далеко от демонстрационного кода здесь . По какой-то причине при передаче массива элементов в компонент функции, который я построил через реквизиты (TimeDisplay), я теряю список. Я получаю пустой Javascript объект для параметра itemsArray вместо фиктивного массива, который был установлен в вызывающем компоновке "Home". Почему бы мне не получить мой маленький массив? Я предполагаю, что это просто я что-то упустил из-за того, как работает React, но я был бы признателен за любую информацию.

Соответствующий код

Home.tsx

import React, { Component } from 'react';
import { TimeSubmitter } from './TimeSubmitter'
import { TimeDisplay, TimeEntry } from './TimeDisplay'

type HomeProps = {

}

export class Home extends Component<HomeProps> {
  static displayName = Home.name;
  private items: TimeEntry[] = new Array<TimeEntry>();

  constructor(props: HomeProps){
    super(props);
    this.items.push(
      {
        client: "Apple",
        hours: 1,
        timeCode: "MD",
        loggedDate: new Date()
    });
  }

  render () {
    return (
      <div>
        <TimeDisplay title="Time Logged this Period" items={this.items} />
      </div>
    );
  }
}

TimeDisplay.tsx

import React, { FunctionComponent, useState } from 'react'; 
import { GroupedList, IGroup } from 'office-ui-fabric-react/lib/GroupedList';
import { IColumn, DetailsRow } from 'office-ui-fabric-react/lib/DetailsList';
import { FocusZone } from 'office-ui-fabric-react/lib/FocusZone';
import { Selection, SelectionMode, SelectionZone } from 'office-ui-fabric-react/lib/Selection';

type TimeDisplayProps = {
    title: string,
    items: TimeEntry[]
  }
export type TimeEntry = {
    client: string,
    hours: number,
    timeCode: string,
    loggedDate: Date
}

const buildGroups = (items: Array<TimeEntry>) => {
    let groups = new Array<IGroup>();
    let hashSet = new Set<string>();
    for (let index = 0; index < items.length; index++) {
        const element = items[index];
        if(!hashSet.has(element.client)){
            groups.push({
                key: element.client,
                name: element.client,
                startIndex: 0,
                count: 10
            });
            hashSet.add(element.client);
        }
      }
      return groups;
    }

const buildColumns = (item: TimeEntry[]) => {
    return (Object.keys(item)
      .map(
        (key: string): IColumn => ({
          key: key,
          name: key,
          fieldName: key,
          minWidth: 300
        })
      ));
}

export const TimeDisplay: FunctionComponent<TimeDisplayProps> = (title, itemsArray) =>{
    const [items, setItems] = useState(itemsArray);
    const [selection, setSelection] = useState(new Selection());
    const [groups, setGroups] = useState(buildGroups(itemsArray));
    const [columns, setColumns] = useState(buildColumns(itemsArray[0]));

    const onRenderCell = (nestingDepth?: number | undefined, item?: any, index?: number | undefined) => {
        if(nestingDepth != undefined && index != undefined){
            return (
                <DetailsRow
                  columns={columns}
                  groupNestingDepth={nestingDepth}
                  item={item}
                  itemIndex={index | 0}
                  selection={selection}
                  selectionMode={SelectionMode.multiple}
                  compact={false}
                />);
        }
    }

    return (        
    <FocusZone>
        <SelectionZone selection={selection} selectionMode={SelectionMode.single}>
          <GroupedList
            items={items}
            onRenderCell={onRenderCell}
            selection={selection}
            selectionMode={SelectionMode.single}
            groups={groups}
          />
        </SelectionZone>
      </FocusZone>);
}

Ответы [ 2 ]

1 голос
/ 15 января 2020

Вам не хватает деструктуризации в вашем определении функционального компонента. Таким образом, функциональные компоненты получают аргумент props в качестве первого параметра, который содержит ВСЕ реквизиты в качестве ключей объекта. Если вы хотите деструктурировать их непосредственно в определении, то вам нужны фигурные скобки. Прямо сейчас itemsArray в вашем функциональном компоненте ссылается на второй аргумент, который получает функциональный компонент, который является ссылкой, перенаправленной с использованием React.forwardRef(...). См. Здесь для получения дополнительной информации .

Итак, определите свой функциональный компонент с помощью фигурных скобок вокруг клавиш поддержки, например:

export const TimeDisplay: FunctionComponent<TimeDisplayProps> = ({title, itemsArray}) =>{
...
1 голос
/ 15 января 2020

this.items - это просто свойство компонента Home. Изменение этого параметра не приведет к повторной визуализации компонента Home или компонента TimeDisplay, которому вы передаете его. Вы также должны деструктурировать ваши реквизиты, полученные в TimeDisplay.

Итак, во-первых, вы должны использовать состояние; в своем конструкторе вы могли бы написать что-то вроде:

import React, { Component } from 'react';
import { TimeSubmitter } from './TimeSubmitter';
import { TimeDisplay, TimeEntry } from './TimeDisplay';

type HomeProps = {};

export class Home extends Component<HomeProps> {
  static displayName = Home.name;
  private items: TimeEntry[] = new Array<TimeEntry>();

  constructor(props: HomeProps) {
    super(props);

    // set initial state with your object inside the items array
    this.state = {
      items: [
        {
          client: 'Apple',
          hours: 1,
          timeCode: 'MD',
          loggedDate: new Date()
        }
      ]
    };
  }

  render() {
    // change this.items to this.state.items
    return (
      <div>
        <TimeDisplay title='Time Logged this Period' items={this.state.items} />
      </div>
    );
  }
}

А затем в TimeDisplay вы должны написать ({title, itemsArray}) вместо (title, itemsArray), поскольку реквизиты передаются как один объект.

I также заметил некоторые другие вещи в вашем коде, к которым вы можете обратиться:

HomeProps, TimeDisplayProps и TimeEntry должны быть interface s, а не типами. Просто измените тип на интерфейс и удалите знак равенства.

Кроме того, более аккуратный способ написать это ...

for (let index = 0; index < items.length; index++) {
        const element = items[index];
        if(!hashSet.has(element.client)){
            groups.push({
                key: element.client,
                name: element.client,
                startIndex: 0,
                count: 10
            });
            hashSet.add(element.client);
        }
      }
      return groups;
    }

Было бы использовать метод forEach в вашем массиве, например. ..

items.forEach(element => {
  if (!hashSet.has(element.client)) {
    groups.push({
      key: element.client,
      name: element.client,
      startIndex: 0,
      count: 10
    });
    hashSet.add(element.client);
  }

  return groups;
});

Надеюсь, все это имеет смысл!

...