How do i acess a useState variable in another component?

64 views Asked by At

I'm a backend engineer trying to work with React. I'm using React Dropzone for file upload but i need to preview the selected image. It works when i preview the image with an Image component within the Dropzone component but i'm looking for a way to access the useState variable that holds the path to the selected image outside the Dropzone component. Please help.

Here's my code:

import { Formik, Form, useField } from 'formik';
import * as Yup from 'yup';
import {FormLabel, Input, Alert, AlertIcon, Image, Box, Button, Stack, VStack} from "@chakra-ui/react";
import {updateCustomer, uploadCustomerProfilePicture} from "../../services/client.js"
import { successNotification, errorNotification } from "../../services/Notification.js"
import {useCallback, useState} from "react";
import {useDropzone} from "react-dropzone";

//const [path, setPath] = useState([]);

let imageUrl = '';

const MyTextInput = ({ label, ...props }) => {
    // useField() returns [formik.getFieldProps(), formik.getFieldMeta()]
    // which we can spread on <input>. We can use field meta to show an error
    // message if the field is invalid and it has been touched (i.e. visited)
    const [field, meta] = useField(props);
    return (
        <Box>
            <FormLabel htmlFor={props.id || props.name}>{label}</FormLabel>
            <Input className="text-input" {...field} {...props} />
            {meta.touched && meta.error ? (
                <Alert className="error" status={"error"} mt={2}>
                    <AlertIcon/>
                    {meta.error}
                </Alert>
            ) : null}
        </Box>
    );
};

const MyDropzone = ({customerId, fetchCustomers}) => {
    const [path, setPath] = useState([]);
    const onDrop = useCallback(acceptedFiles => {
        setPath(acceptedFiles.map(file => URL.createObjectURL(file)))

        const formData = new FormData();
        formData.append("file", acceptedFiles[0])
        // Do something with the files
        uploadCustomerProfilePicture(
            customerId, formData
        ).then(() => {
            successNotification("Success","Profile picture uploaded")
            fetchCustomers()
        }).catch(() => {
            errorNotification("Error","Profile picture upload failed")
        })
        console.log(`localhost:8080/api/v1/customers/${customerId}/profile-image`);
    }, [])
    const {getRootProps, getInputProps, isDragActive} = useDropzone({onDrop})

    return (
        <Box {...getRootProps()}
             w={'100%'}
             textAlign={'center'}
             border={'dashed'}
             borderColor={'gray.200'}
             borderRadius={'3xl'}
             p={6}
             rounded={'md'}
        >
            <input {...getInputProps()} />
            {
                isDragActive ?
                    <p>Drop the picture here ...</p> :
                    <p>Drag 'n' drop picture here, or click to select picture</p>
            }

            {path.map(paths =>
                <Image
                    borderRadius={'full'}
                    boxSize={'150px'}
                    objectFit={'cover'}
                    src={paths}
                    key={paths}
                />
            )
            }
        </Box>
    )
}


// And now we can use these
const UpdateCustomerForm = ({ fetchCustomers, initialValues, customerId }) => {
    return (
        <>
            <VStack spacing={'5'} mb={'5'}>
                <Image
                    borderRadius={'full'}
                    boxSize={'150px'}
                    objectFit={'cover'}
                    src={`http://localhost:8080/api/v1/customers/${customerId}/profile-image`}
                />

               <MyDropzone customerId={customerId} fetchCustomers={fetchCustomers}/>
            </VStack>
            <Formik
                initialValues={initialValues}
                validationSchema={Yup.object({
                    name: Yup.string()
                        .max(15, 'Must be 15 characters or less')
                        .required('Required'),
                    email: Yup.string()
                        .email('Invalid email address')
                        .required('Required'),
                    age: Yup.number()
                        .min(16, 'Must be at least 16 years of age')
                        .max(100, 'Must be less than 100 years of age')
                        .required('Required'),
                })}
                onSubmit={(updatedCustomer, { setSubmitting }) => {
                    setSubmitting(true);
                    updateCustomer(customerId, updatedCustomer)
                        .then(res => {
                            console.log(res);
                            successNotification(
                                "Customer updated",
                                `${updatedCustomer.name} was successfully updated`
                            )
                            fetchCustomers();
                        }).catch(err => {
                            console.log(err);
                            errorNotification(
                                err.code,
                                err.response.data.message
                            )
                    }).finally(() => {
                        setSubmitting(false);
                    })
                }}
            >

                {({isValid, isSubmitting, dirty}) => (
                    <Form>
                        <Stack spacing={"24px"}>
                            <MyTextInput
                                label="Name"
                                name="name"
                                type="text"
                                placeholder="Jane"
                            />

                            <MyTextInput
                                label="Email Address"
                                name="email"
                                type="email"
                                placeholder="[email protected]"
                            />

                            <MyTextInput
                                label="Age"
                                name="age"
                                type="number"
                                placeholder="20"
                            />

                            <Button
                                isDisabled={ !(isValid && dirty) || isSubmitting }
                                mt={4}
                                type={"submit"}
                                colorScheme={"red"}
                            >Submit</Button>
                        </Stack>
                    </Form>
                )}

            </Formik>
        </>
    );
};


export default UpdateCustomerForm;

I need a way to access the path variable in the updateCustomerForm component.

1

There are 1 answers

0
noob7 On

Since react is one way data flow, u cant access child component states from parent. You have two options, either move the value in context. Which might be slightly involved as you mentioned you are beginner. Easier solution is to just hoist the state value in the parent component 'updateCustomerForm' and pass both the value and the setter to the dropzone component