• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Wizard form in React TypeScript react-final-form

Cloud VPS
0 głosów
347 wizyt
pytanie zadane 8 lipca 2020 w JavaScript przez poldeeek Mądrala (5,980 p.)

Próbuje napisać 3 krokowy formularz za pomocą react-final-form przy użyciu TypeScript. Mocno wzorowałem się na tym przykładzie - codesandbox, jednak nie za bardzo rozumiem jak działa zapis <Wizard.Page> przez co nie mam pojęcia w jaki sposób "przerzuć" to na TypeScript. Próbowałem dać zmienną Page jako const, jendak chyba nie tędy droga... Jak dotąd jestem na takim etapie :

register.tsx

import React from "react";
import Wizard from "./wizard";

import styles from "./register.module.scss";

const Register: React.FC = () => {
  const onSubmit = () => {
    console.log("onSubmit");
  };

  return (
    <Wizard onSubmit={onSubmit}>
      <Wizard.Page>
        
      </Wizard.Page>
    </Wizard>
  );
};

export default Register;

Wizard.tsx

import React, { useState } from "react";
import { Form } from "react-final-form";

type Wizard = {
  onSubmit: (values: Values) => void;
};

type Values = {
  name: String;
  surname: String;
  email: String;
  password: String;
  city: String;
  birthDay: Number;
  birthMonth: Number;
  birthYear: Number;
};

// 3-steps form
const Wizard: React.FC<Wizard> = ({ onSubmit, children }) => {
  const [page, setPage] = useState(0);
  const [values, setValues] = useState<Values | undefined>(undefined);
  const activePage = React.Children.toArray(children)[page];
  const isLastPage = page === React.Children.count(children) - 1;

  const Page = (children: React.ReactChildren) => children;

  // next page
  const next = (values: Values) => {
    setPage(Math.min(page + 1, React.Children.count(children)));
    setValues(values);
  };

  // previous page
  const previous = () => {
    setPage(Math.max(page - 1, 0));
  };

  const handleSubmit = (values: Values) => {
    const isLastPage = page === React.Children.count(children) - 1;
    if (isLastPage) {
      return onSubmit(values);
    } else {
      next(values);
    }
  };

  return (
    <Form onSubmit={handleSubmit}>
      {({ handleSubmit, submitting, values }) => {
        <form onSubmit={handleSubmit}>
          {activePage}
          <div className="buttons">
            {page > 0 && (
              <button type="button" onClick={previous}>
                « Powrót
              </button>
            )}
            {!isLastPage && <button type="submit">Dalej »</button>}
            {isLastPage && (
              <button type="submit" disabled={submitting}>
                Zakończ
              </button>
            )}
          </div>
        </form>;
      }}
    </Form>
  );
};

export default Wizard;

 

1 odpowiedź

0 głosów
odpowiedź 8 lipca 2020 przez Wiciorny Ekspert (281,450 p.)
 <Wizard.Page>
         
      </Wizard.Page>

to mi wygląda na komponent dodatkowy 

Wizard ma w swojej implementacji obiekt PAGE, i odwoładnie jest do obiektu Page- componentu Page znajdującego się w klasie wizard 
 

class Wizard extends React.Component {
  static Page = ({ children }) => children
class Wizard extends React.Component {
  static Page = ({ children }) => children

  state = {
    currentPage: 0,
  }

  get isLastPage() {
    const children = this.props.children;
    const currentPage = this.state.currentPage;
    return currentPage === React.Children.count(children) - 1;
  }

  get activePage() {
    const currentPage = this.state.currentPage;
    const children = this.props.children;
    const activePage = React.Children.toArray(children)[currentPage];
    return activePage;
  }

  handleNext = (values) => {
    const children = this.props.children;
    this.setState(prevState => ({
      currentPage: Math.min(prevState.currentPage + 1, children.length - 1),
      values,
    }));
  }

  handlePrevious = () => {
    this.setState(prevState => ({
      currentPage: Math.max(prevState.currentPage - 1, 0),
    }));
  }

  // Both validate and handleSubmit switching are implemented
  // here because Redux Final Form does not accept changes to those
  // functions once the form has been defined.
  validate = (values) => {
    const { props } = this.activePage;
    return props.validate ? props.validate(values) : {};
  }

  handleSubmit = (values) => {
    if (this.isLastPage) {
      return this.props.onSubmit(values);
    }
    return this.handleNext(values);
  }

  render() {
    const { currentPage, values: prevValues } = this.state;
    return (
      <Form
        initialValues={prevValues}
        validate={this.validate}
        onSubmit={this.handleSubmit}
      >
        {({ handleSubmit, submitting }) => (
          <form onSubmit={handleSubmit}>
            {this.activePage}
            <div>
              <div className={styles.buttons}>
                {currentPage > 0 && (
                  <Button
                    primary
                    iconOnLeft
                    type="button"
                    onClick={this.handlePrevious}
                    icon={angleArrowLeft}
                  >
                    Previous
                  </Button>
                )}
                {this.isLastPage ? (
                  <Button
                    primary
                    type="submit"
                    disabled={submitting}
                    icon={submitting ? spinnerIcon : checkMarkIcon}
                  >
                    {this.props.submitText}
                  </Button>
                ) : (
                  <React.Fragment>
                    <Button danger icon={crossIcon} onClick={this.props.onClose}>
                      Cancel
                    </Button>
                    <Button primary type="submit" icon={angleArrowRight}>
                      Continue
                    </Button>
                  </React.Fragment>
                )}
              </div>
            </div>
          </form>
        )}
      </Form>
    );
  }
}

Wizard.propTypes = {
  children: PropTypes.node.isRequired,
  onClose: PropTypes.func.isRequired,
  onSubmit: PropTypes.func.isRequired,
  submitText: PropTypes.string,
};

Wizard.defaultProps = {
  submitText: 'Submit',
};

export default Wizard;

 

komentarz 8 lipca 2020 przez poldeeek Mądrala (5,980 p.)

Nie za bardzo rozumiem co to jest komponent dodatkowy...
Z tego co ja zauważyłem w Wizard.js jest zmienna statyczna : 
 

  static Page = ({ children }) => children

i to jest właściwie jedyna wzmianka w całym sandbox'ie o elemencie Page.. 
Problem polega na tym, że jeśli chcę stworzyć taką zmienną w TypeScript 

  const static Page = (children: React.ReactChildren) => children;

dostaję taki błąd na static : 

const static: any
Variable 'static' implicitly has an 'any' type.ts(7005)

i taki nad Page :
 

const Page: (children: React.ReactChildren) => React.ReactChildren
',' expected.ts(1005)

 

komentarz 8 lipca 2020 przez Wiciorny Ekspert (281,450 p.)

no i teraz trzeba znać jak wygląda komponent PAGE. 
Skoro odwołanie mamy do statycznego pola w klasie to normalny jest zapis


KlasaNadrzędna.obiektStatyczny 

 

komentarz 8 lipca 2020 przez Wiciorny Ekspert (281,450 p.)

tu się kłania wydaje mi się kompozycja i iinicjalizacja zmiennej children przez PROPSALA
https://pl.reactjs.org/docs/composition-vs-inheritance.html

komentarz 8 lipca 2020 przez poldeeek Mądrala (5,980 p.)

Page jest tworzona po prostu w komponencie nadrzędnym w taki sposób :
 

<Wizard
      initialValues={{ employed: true, stooge: 'larry' }}
      onSubmit={onSubmit}
    >
      <Wizard.Page>
        <div>
          <label>First Name</label>
          <Field
            name="firstName"
            component="input"
            type="text"
            placeholder="First Name"
            validate={required}
          />
          <Error name="firstName" />
        </div>
        <div>
          <label>Last Name</label>
          <Field
            name="lastName"
            component="input"
            type="text"
            placeholder="Last Name"
            validate={required}
          />
          <Error name="lastName" />
        </div>
      </Wizard.Page>
</Wizard>

I potem w Wizard jest tylko ta zmienna statyczna Page. 

  static Page = ({ children }) => children

Rozumiem jak działa children i kompozycja, do której linka podałeś. Kompletnie nie rozumiem jednak tego zapisu i odwołania. Tworzy się funkcję statyczną Page, która jako argument dostaje children. Nie ma nawet odwołania props.children ani nic... Po prostu nie rozumiem co taka funkcja miałaby robić i czemu służyć. 

Podobne pytania

0 głosów
0 odpowiedzi 159 wizyt
pytanie zadane 4 października 2023 w JavaScript przez reaktywny Nałogowiec (46,230 p.)
0 głosów
1 odpowiedź 439 wizyt
0 głosów
2 odpowiedzi 809 wizyt
pytanie zadane 12 marca 2022 w JavaScript przez jarusek13 Początkujący (310 p.)

93,460 zapytań

142,454 odpowiedzi

322,724 komentarzy

62,838 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Kursy INF.02 i INF.03
...