Passing props to children in React

11,517

Solution 1

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.

Solution 2

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} />}
        />
    )
}
Share:
11,517
Bart
Author by

Bart

Updated on June 22, 2022

Comments

  • Bart
    Bart almost 2 years

    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?