Como alterar a forma do Antd initialValues ​​depende do url ou id?

Oct 26 2020

Eu tenho o mesmo componente com o formulário Antd para adicionar / editar artigo. Com pathes no roteador

<Route path="/add" component={ !currentUser ? Login : ArticleEditor } />
<Route path="/article/:id/edit" component={ !currentUser ? Login : ArticleEditor } />

Quando clico no botão "editar", adiciono initialValues ​​ao formulário, do que se clicar em "Criar novo artigo" o url muda para "/ adicionar", mas o formulário não atualiza os valores. Os valores permanecem do artigo editado. Como atualizar os valores do formulário? Tentei definir initialValues ​​depende do caminho, ou "id", mas não funcionou. Como atualizar os valores do formulário antd nesse caso?

const initialValues = this.props.location.pathname === '/add' ? {} : {
      title: this.props?.title,
      body: this.props?.body,
      description: this.props?.description
    };

Aqui você pode ver o código do componente - link codesandbox

Respostas

1 DipenShah Nov 02 2020 at 12:01

O principal problema com o código é que os campos do formulário não são redefinidos quando o url é alterado, você pode detectar a alteração do caminho shouldComponentUpdatee definir isLoadingcomo truee o resto deve funcionar.

A atualização initialValuesnão funcionará porque a antdcomparação é superficial e, uma vez que os valores iniciais são definidos, você não poderá alterá-los.

Havia um problema cuja lógica componentDidUpdatetambém corrigia.

import React from "react";
import ErrorsList from "../ErrorsList/ErrorsList";
import userService from "../../services/userService";
import { connect } from "react-redux";
import { push } from "react-router-redux";
import { Form, Input, Button } from "antd";
import { store } from "../../store";
import actionCreators from "../../actionCreators";

const formItemLayout = {
  labelCol: { span: 24 },
  wrapperCol: { span: 24 }
};

const formSingleItemLayout = {
  wrapperCol: { span: 24, offset: 0 }
};

const mapStateToProps = (state) => ({
  ...state.editor
});

const mapDispatchToProps = (dispatch) => ({
  onLoad: (payload) => dispatch(actionCreators.doEditorLoaded(payload)),
  onUnload: () => dispatch(actionCreators.doEditorUnloaded()),
  onUpdateField: (key, value) =>
    dispatch(actionCreators.doUpdateFieldEditor(key, value)),
  onSubmit: (payload, slug) => {
    dispatch(actionCreators.doArticleSubmitted(payload));
    store.dispatch(push(`/`)); //article/${slug}
  },
  onRedirect: () => dispatch(actionCreators.doRedirect())
});

class ArticleEditor extends React.Component {
  constructor(props) {
    super(props);
    this.id = this.props.match.params.id;
    const updateFieldEvent = (key) => (e) =>
      this.props.onUpdateField(key, e.target.value);
    this.changeTitle = updateFieldEvent("title");
    this.changeDescription = updateFieldEvent("description");
    this.changeBody = updateFieldEvent("body");
    this.changeTagInput = updateFieldEvent("tagInput");
    this.isLoading = true;

    this.submitForm = () => {
      const article = {
        title: this.props.title,
        description: this.props.description,
        body: this.props.body,
        tagList: this.props.tagInput.split(",")
      };

      const slug = { slug: this.props.articleSlug };
      const promise = this.props.articleSlug
        ? userService.articles.update(Object.assign(article, slug))
        : userService.articles.create(article);

      this.props.onSubmit(promise, this.props.articleSlug);
    };
  }

  componentDidUpdate(prevProps, prevState) {
    if (this.props.match.params.id !== prevProps.match.params.id) {
      if (prevProps.match.params.id) {
        this.props.onUnload();
      }

      this.id = this.props.match.params.id;
      if (this.id) {
        return this.props.onLoad(userService.articles.get(this.id));
      }

      this.props.onLoad(null);
    }

    this.isLoading = false;
  }

  componentDidMount() {
    if (this.id) {
      this.isLoading = true;
      return this.props.onLoad(userService.articles.get(this.id));
    }
    this.isLoading = false;
    this.props.onLoad(null);
  }

  componentWillUnmount() {
    this.props.onUnload();
  }

  shouldComponentUpdate(newProps, newState) {
    if (this.props.match.params.id !== newProps.match.params.id) {
      this.isLoading = true;
    }

    return true;
  }

  render() {
    const { errors } = this.props;
    const initialValues = {
      title: this.props?.title,
      body: this.props?.body,
      description: this.props?.description,
      tags: this.props?.tagList
    };

    return this.isLoading ? (
      "loading..."
    ) : (
      <div className="editor-page">
        <div className="container page">
          <div className="">
            <div className="">
              <ErrorsList errors={errors}></ErrorsList>
              <Form
                {...formItemLayout}
                initialValues={initialValues}
                onFinish={this.submitForm}
              >
                <Form.Item
                  label="Title"
                  name="title"
                  placeholder="Article Title"
                  rules={[
                    {
                      required: true,
                      message: "Please input article title"
                    }
                  ]}
                >
                  <Input onChange={this.changeTitle} />
                </Form.Item>
                <Form.Item
                  label="Description"
                  name="description"
                  placeholder="Short description"
                  rules={[
                    {
                      required: true,
                      message: "Please input article description"
                    }
                  ]}
                >
                  <Input onChange={this.changeDescription} />
                </Form.Item>
                <Form.Item
                  name="body"
                  label="Article Text"
                  placeholder="article text"
                >
                  <Input.TextArea onChange={this.changeBody} />
                </Form.Item>
                <Form.Item name="tags" label="Tags" placeholder="Enter tags">
                  <Input onChange={this.changeTagInput} />
                </Form.Item>
                <Form.Item {...formSingleItemLayout}>
                  <Button
                    className="editor-form__btn"
                    type="primary"
                    htmlType="submit"
                    disabled={this.props.inProgress}
                  >
                    Submit Article
                  </Button>
                </Form.Item>
              </Form>
            </div>
          </div>
        </div>
      </div>
    );
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(ArticleEditor);

dê uma olhada nesta caixa de códigos bifurcada .

1 shahriarhasan Nov 02 2020 at 15:59

Você deve limpar os campos antes de reutilizar o componente 'ArticleEditor'. Aqui você está usando o mesmo componente para duas rotas diferentes, portanto, ele não muda.

Você deve verificar se está editando ou adicionando uma nova entrada ao Editor. Seu componente de editor pode ter a seguinte aparência,

const ArticleEditor = props => {
   const [form] = Form.useForm();
   useEffect(() => {
      if (props.match.params.id) form.setFieldsValue({value : 'Some values'})
      else form.resetFields()
   }, [props?.match?.params]);

   return (
      <Form form={form} onFinish={yourFinishMethod}>
          //...your form fields
      </Form>
   )
}