最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Passing props to children in React - Stack Overflow

programmeradmin0浏览0评论

I'm trying to make a Formik wrapper which takes children as props and would render anything put inside. There are a couple forms to make which take different initial values and validation schema etc. The only thing in common thing is the grid layout. The goal is to have the access to Formik props like values, errors etc. in the child component and I have no idea how to pass it to its child. The form fields don't even show up.

The wrapper:

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;

I must be doing something wrong. I am unable to get any Formik props/values from anywhere else when I wrap FormContainer around anything.

My form example (so far):

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;

I'm stuck. What am I doing wrong here?

I'm trying to make a Formik wrapper which takes children as props and would render anything put inside. There are a couple forms to make which take different initial values and validation schema etc. The only thing in common thing is the grid layout. The goal is to have the access to Formik props like values, errors etc. in the child component and I have no idea how to pass it to its child. The form fields don't even show up.

The wrapper:

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;

I must be doing something wrong. I am unable to get any Formik props/values from anywhere else when I wrap FormContainer around anything.

My form example (so far):

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;

I'm stuck. What am I doing wrong here?

Share Improve this question edited Dec 18, 2019 at 0:02 Bart asked Dec 17, 2019 at 23:32 BartBart 1722 gold badges5 silver badges12 bronze badges 1
  • Just at first glance, you're using props twice, once when destructuring the arguments passed to your wrapper, and then again to name the arguments for the child render function. That seems a little weird to me; I think my IDE would be highlighting that as an error :) – larz Commented Dec 18, 2019 at 0:22
Add a comment  | 

2 Answers 2

Reset to default 13

Here's how to pass the prop "propsToPass" from the parent to all his direct children:

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;

So in this case, both children will have the prop "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>

You could do the same for your form.

I don't see like rendering Formik as children is good idea here, especially that you are supposed to render one form in such FormWrapper. I would use render props here, so here is basic example how you can do it.

Anyway, I still can't get your concept of re-inventing FormWrapper if Formik provides its own wrapper:

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} />}
        />
    )
}
发布评论

评论列表(0)

  1. 暂无评论