在React中将道具传递给孩子

时间:2019-12-17 23:32:57

标签: javascript reactjs typescript forms formik

我正在尝试制作一个{strong> Formik包装器,该包装器以children作为道具,并且会呈现其中的任何内容。有几种形式可以采用不同的初始值和验证模式等。唯一的共同之处是网格布局。目标是可以访问子组件中的 Formik props ,例如值,错误等,我不知道如何将其传递给子组件。表单字段甚至都不会显示。

包装器

import React from 'react';
import { Formik, FormikConfig, FormikValues } from "formik";
import { Col, Layout, Row } from "antd";

const FormContainer: React.FC<FormikConfig<FormikValues>> = ({ children, ...props }) => {
    return <Formik
        {...props}
    >
        {props => (
            <Layout>
                <Row style={{ height: "100vh", display: "flex", alignItems: "center" }}>
                    <Col span={12}>
                        <Layout>
                            {/*this will be replaced with some background image*/}
                            <pre>{JSON.stringify(props.values, null, 2)}</pre>
                            <pre>{JSON.stringify(props.errors, null, 2)}</pre>
                        </Layout>
                    </Col>
                    <Col span={12}>
                        <Layout>
                            {/*here goes goes a Form from a different components*/}
                            {children}
                        </Layout>
                    </Col>
                </Row>
            </Layout>
        )}
    </Formik>
};

export default FormContainer;

我一定做错了。当我将FormContainer包装在任何东西上时,我无法从其他任何地方获得任何Formik道具/价值。

我的表单示例(到目前为止):

import React from "react";
import { Field, Form } from "formik";
import { Col, Form as AntForm, Icon, Input, Row } from "antd";
import { initialValues, validationSchema } from "./fieldValidation";
import FormContainer from "../../../containers/FormContainer/FormContainer";

const RegisterPage: React.FC = () => {
    return (
        <FormContainer
            initialValues={initialValues}
            validationSchema={validationSchema}
            onSubmit={(data, { setSubmitting }) => {
                setSubmitting(true);

                setTimeout(() => {
                    alert(JSON.stringify(data, null, 2));
                    setSubmitting(false);
                }, 5000);
            }}
        >
            {({touched, errors}) => (
                <Form>
                    <Row gutter={[8, 8]}>
                        <Col span={12}>
                            <AntForm.Item
                                help={touched.firstName && errors.firstName ? errors.firstName : ""}
                                validateStatus={touched.firstName && errors.firstName ? "error" : undefined}
                            >
                                <Field
                                    name="firstName"
                                    prefix={<Icon type="solution" style={{ color: "rgba(0,0,0,.25)" }} />}
                                    placeholder="First name"
                                    as={Input}
                                />
                            </AntForm.Item>
                        </Col>
                        <Col span={12}>
                            <AntForm.Item
                                help={touched.lastName && errors.lastName ? errors.lastName : ""}
                                validateStatus={touched.lastName && errors.lastName ? "error" : undefined}
                            >
                                <Field
                                    name="lastName"
                                    prefix={<Icon type="solution" style={{ color: "rgba(0,0,0,.25)" }} />}
                                    placeholder="Last name"
                                    as={Input}
                                />
                            </AntForm.Item>
                        </Col>
                    </Row>
                </Form>
            )}
        </FormContainer>
    );
};

export default RegisterPage;

我被困住了。我在这里做什么错了?

3 个答案:

答案 0 :(得分:0)

将props传递到用作this.props.children的子组件:
文件React Top-Level API中的结帐React.cloneElementQA

答案 1 :(得分:0)

以下是将道具“ propsToPass”从父母传递给他所有直系子女的方法:

const Parent = props => {
  const { children } = props;

  const childrenWithExtraProp = React.Children.map(children, child =>
    React.cloneElement(child, { propsToPass: "toChildren" })
  );

  return <div>{childrenWithExtraProp}</div>;
};

export default Parent;

因此,在这种情况下,两个孩子都将拥有道具“ propsToPass”

<Parent>
  {/* this.props.propsToPass will be available in this component */}
  <Child></Child>
  {/* this.props.propsToPass will be available in this component */}
  <AnotherChild></AnotherChild>
</Parent>

您可以为表单做同样的事情。

答案 2 :(得分:0)

我不认为像儿童一样将Formik呈现为一个好主意,尤其是应该使用FormWrapper呈现一种形式。我将在此处使用渲染道具,因此这是如何实现的基本示例。

无论如何,如果Formik提供了自己的包装器,我仍然无法理解您重新发明FormWrapper的概念:

https://jaredpalmer.com/formik/docs/api/formik

interface FormWrapperProps extends FormikConfig<FormikValues> {
    renderForm(props: FormWrapperProps): React.ReactNode
}

export const RegisterForm = (props: FormWrapperProps) => (
    <form>
        <input type="text"/>
        <input type="text"/>
    </form>
)

const FormWrapper: React.FC<FormWrapperProps> = (props) => {
    return (
        <div className="layout">
            {/*here goes goes a Form from a different components*/}
            {props.renderForm(props)}
        </div>
    )
}

const FormPage = () => {

    const props = {} as FormWrapperProps

    return (
        <FormWrapper
            {...props}
            renderForm={(props: FormWrapperProps) => <RegisterForm {...props} />}
        />
    )
}