0

I'm having a functional components, where parent retrieves data from couple of arrays from API and passes them as single object to children. I get the data in parent's useEffect. Unfortunately it seems I'm not getting any data to the component, when debugging the dictionary object in child looks empty.

So in my parent tsx (cutted out nonimportant parts):

export default function RozliczeniaFaktur ({web, context, formType}: IRozliczeniaFakturProps) {
    const [dataRows, setDataRows] = React.useState(emptyRowArr);
    const [isError, setIsError] = React.useState(false);
    const [errorMessage, setErrorMessage] = React.useState(null);
    const [dictionary, setDictionary] = React.useState<IDictionary>({
      organizacja: [], mpk: [], vat: [], zastepstwa: [], konto: []
    });
    
    const initDictionary = () => {
      let dict : IDictionary = {
        organizacja: [], mpk: [], vat: [], zastepstwa: [], konto: []
      };
      web.lists.getByTitle("Organizacja").items.get().then((items: any[])=> {
        dict.organizacja = items;
      }, (e: any) => setError(`"Błąd pobierania listy Organizacja: ${e}"`));
        // ommited for brevity
      setDictionary(dict);
    }

    React.useEffect(() => {
      initDictionary();

    },[]);

    const addRow = (rowId: number) => {
      let d = dataRows;
      let i = dataRows[rowId];
      d.push(i);
      setDataRows(d);
    }

    return (
      
      <div className={styles.rozliczeniaFaktur}>
             {dataRows && 
                dataRows.map((dataRow, i) => {
                  return <TableRowControl web={web} key={i} Context={context} RowId={i} PozFaktury={dataRow} FormType={formType}
                    onAddRowCallback={addRow} onDeleteRowCallback={delRow} Dictionary={dictionary}  />
                })
              }

    </div>
    );
  
}

And in child tsx:

import * as React from 'react';
import styles from './TableRowControl.module.scss';
import {IPozFaktury} from '../IPozFaktury';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { DateTimePicker, DateConvention, IDateTimePickerStrings } from '@pnp/spfx-controls-react/lib/DateTimePicker';
import { Dropdown, IDropdownOption, IDropdownStyles } from 'office-ui-fabric-react/lib/Dropdown';
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
import { PeoplePicker, PrincipalType } from "@pnp/spfx-controls-react/lib/PeoplePicker";
import { WebPartContext } from '@microsoft/sp-webpart-base';
import { DayOfWeek } from 'office-ui-fabric-react';
import { Web } from '@pnp/sp';
import { IconButton } from 'office-ui-fabric-react/lib/Button';
import { IDictionary } from '../IDictionary';

export interface ITableRowControlProps {
    RowId: Number;
    PozFaktury: IPozFaktury;
    FormType: String;
    Context: WebPartContext;
    web: Web;
    Dictionary: IDictionary;

    onAddRowCallback?: (...event: any[]) => void;
    onDeleteRowCallback?: (...event: any[]) => void;
    onErrorCallback?: (...event: any[]) => void;
}

const TableRowControl = ({RowId, Context, PozFaktury, FormType, onAddRowCallback, onDeleteRowCallback, web, Dictionary, onErrorCallback} : ITableRowControlProps) => {   
    const [oddzialRozliczeniaOptions, setOddzialRozliczeniaOptions] = React.useState<IDropdownOption[]>([]);
    const [vatOptions, setVatOptions] = React.useState<IDropdownOption[]>([]);
    const [mpkOptions, setMpkOptions] = React.useState<IDropdownOption[]>([]);
    const [kontoGlOptions, setKontoGlOptions] = React.useState<IDropdownOption[]>([]);
    const [zaliczkaOptions, setZaliczkaOptions] = React.useState<IDropdownOption[]>([]);
    const [isPZrequired, setIsPZrequired] = React.useState(false);




    return(
        <tr>
            <td className={styles.cell}>
                <IconButton onClick={()=> onAddRowCallback(RowId)} iconProps={{ iconName: 'Add' }} title="Dodaj" ariaLabel="Dodaj" />
                <IconButton onClick={()=> onDeleteRowCallback(RowId)} iconProps={{ iconName: 'Delete' }} title="Usuń" ariaLabel="Usuń" />
            </td>
            {/* Oddzial rozliczenia */}
            <td  className={styles.cell}>
                <Dropdown options={Dictionary.organizacja.map(i => {return { key: i.Title, text: i.Organizacja }})} selectedKey={PozFaktury.OddzialRozliczenia}  />
            </td>

        </tr>
        );
}

export default TableRowControl;

I'm getting no options in dropdowns (works when bound to static array), and when debugging, the Dictionary object in child looks like in it's initial state in parent (with empty arrays).

EDIT:

OK, i seem to have solved the first issue, but now I've got another similar one. When I press 'Add', it looks like the code is adding a copy of a row to array dataRows (correctly), but on screen it's still one row. Where is the problem?

n0e
  • 309
  • 3
  • 12
  • You call an async method. You set the dictionary to initial state. You get the response and try to mutate state. React doesn't pick up mutation. Try setting state inside `then` – Nadia Chibrikova Mar 13 '21 at 14:18
  • @NadiaChibrikova this means that I won't be able to set just one property of the Dictionary object, I will have to split the object into it's properties, and put them into state through useState hooks? because I will be setting one property at a time. – n0e Mar 13 '21 at 16:02
  • You need to create a new object each time you call setState, you can't update just one field. Either split your state into smaller objects, or clone the single time each time you update a property (shallow clone will do) – Nadia Chibrikova Mar 13 '21 at 17:32
  • @NadiaChibrikova thanks for your help, could you take a look on my second question (made an edit)? – n0e Mar 13 '21 at 18:14
  • same issue, you need to clone the rows (`d =[...dataRows]`), then clone the row you want to copy, and potentially clone elements in that row too (if elements are simple types like numbers or stings they'll be fine, but if they're objects you won't be able to edit them independently unless you clone them) – Nadia Chibrikova Mar 13 '21 at 18:34
  • @NadiaChibrikova thank you, btw could you take a look at my other question? https://stackoverflow.com/questions/66619104/react-get-data-from-child-functional-components-in-parent – n0e Mar 14 '21 at 12:15

0 Answers0