Jordan
Jordan

Reputation: 117

How to Pass React form state from app to multiple components (functional)

I'm still fairly new to React, so I'm sorry if this is a repetitive post. I'm working with React to create a form that spreads across different pages. The idea is to have the type of form you'd receive from a job application. One that has multiple steps.

I have different components made for each step of the form. The first page is a home page. Imagine a button to take you to the create page. Then you see the Create page. There is a small form with an amount and name. When you click the next page, you'll see the Customize page. There you can edit your budget by priority.

enter image description here

Here in my poorly drawn picture, I have the app obviously, and a budget homepage to manage state across it's children. I figured I should do it this way because, well it's the only way I know how. The problems I have, are one: I don't know how to properly pass state throughout the components. Two: I don't even know if what I'm doing is correct. The React docs use forms in Class based components, which sort of helps, but I can't configure it to my problem.

Any help or suggestions are greatly appreciated. Also I want to show code from the Budget Page.

import React, { useState, useEffect, useRef } from "react";
import BudgetResultsPage from './BudgetResultsPage';

const [count, setState] = useState(0);
const handleStateCount = () => {
        if(count>3) {count = 0;}
        return setState(count + 1);
    }
if(count === 0) {
        console.log(`homepage state ${count}`)
        return (
            <div className={Styles.Calculator}>
                <BudgetHomePage setState={count} handleStateCount={handleStateCount}/>
            </div>
        )
    } else if(count===1) {
        console.log(`budget create state ${count}`)
        return (
            <div className={Styles.Calculator}>
                <CalculatorHeader />
                <CreateBudget setState={count} handleStateCount={handleStateCount} setAmount={amount} handleAmount={handleAmount}/>
            </div>
        )}

There are obviously more imports for the other pages and more code passed in the component. This is just a snippet of the way I'm handling the components.

It's probably silly, but I'm creating a count in state, then when part of the form is submitted, the count goes up and it changes the page based on what the count is at. Works great for just one state, but I'm having problems with adding more state to it.

Thanks again!

Upvotes: 0

Views: 974

Answers (2)

Agustin Moles
Agustin Moles

Reputation: 1534

Which kind of problems are you experiencing? I assume that the part of code you left there is inside a component body (a function, as you are using functional way).

You should have no problems passing multiple props to child components even though you have to keep in mind other approaches (excesive number of props means something is wrong in general...)

Let me know if you have more questions.

EDIT:

Suppose you have that ResultsPage child component and in your parent component you do something like:

<ResultsPage someProp={someValue} someOtherProp={someOtherValue} />

Then in your child component you can manage those props like this:

const ResultsPage = (props) => {
   // props is an object like this: { someProp: someValue, someOtherProp: someOtherValue}
   ...  // and in the body of the function you can manipulate it however you want
}

Generally it is better to destructure your props variable in the param directly instead of always do props.someProp, etc. like this:

const ResultsPage = ({someProp, someOtherProp}) => { ... }

More info about destructure here

Upvotes: 0

Null
Null

Reputation: 119

I have written an example functional components illustrating some of your questions. I wrote this at home and only had notepad++ so might not compile if you copy paste. The comments will explain your questions

import React from 'react';
import Create_budget_page from './Create_budget_page.js';


const BudgetPage = props => {

    // State 1: assigning one value to the state.
    // State 2: assinging a list to the state.
    // State 3: assinging a object to the state.
    const [simple_state, set_simple_state] = useState(false);
    const [list_state, set_list_state] = useState(["Hello","World","!"]);
    const [object_state, set_object_state] = useState(
        {
            curmenu: "human_bios",
            height: "196cm", 
            weight: "174lbs", 
            eye_colour: "blue", 
            hair_colour: "dirty_blonde"
        }
    );
    // there are several possiblities, here's one with a list of objects
    const [list_objects, set_list_objects] = useState(
        [
            {count: 69, wasClicked: false},
            {count: 420, wasClicked: true},
            // endless possibilities, the tricky part is properly correctly updating your states deep in the list
            {integers: [1,5,2,3], keys: {isAlive: false, cur_menu: "config_menu"}}
        ]
    );

    // this function updates the state that stores an object
    // arguments:
    //      new_values_object: the programmer passes in a object to the function with the values they want to update
    //      an example of calling this function in a child functional component:
    //          props.update_object_state({height: "165cm", weight: "143lbs", hair_colour: "black"});
    function update_object_state(new_values_object){
        set_object_state(prevState => {
            const new_obj = prevState;
            // loop through object keys and update the new_obj with the object passed in as a argument
            for (var key in new_values_object){
                new_obj[key] = new_values_object[key];
            }
            // returning the new_object will update the object_state
            return new_obj;
        })
    }



    // conditionally render based on state
    
    switch(object_state["curmenu"]){
        case "home_page":
             return (
                // pass in 
                // all props, 1 prop, state
                <Create_budget_page  {...props}  parent_id={prop.parent_id} simple_state={simple_state} list_objects={list_objects}/>
             ) ;
             break;
        // pass in function
        case "human_bios":
            return (
                <div className="error_page" onClick={() => {props.update_parent_state({error_occured: true})}}>This is an Error Page, click me to report diagnostics</div>
            );
        break;
        // if none of cases are met default code executes
        default:
            // renders nothing 
            return null;
    }        
}

Upvotes: 1

Related Questions