Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing data from same level components React

Tags:

reactjs

I have a HealthForm component where the user enters an url in a text input and clicks a button to submit. I have that url saved as a state in the component and I call some APIs which are all working. The problem is that I have several other components that need that url and I can't seem to find a way to pass it to them.

My App.js looks like this which is why all other posts/tutorials are confusing me.

class App extends React.Component {
  render(){
    return(
        <MuiThemeProvider>
            <Router>
                <div className="App">

                    <Route path="/" component={()=>(
                        <div>
                            <Header/>
                            <HealthForm/>
                        </div>)}/>

                    <Route path="/path1" component={ProductForm}></Route>
                    <Route path="/path2" component={xForm}></Route>
                    <Route path="/path3" component={yForm}></Route>
                    <Route path="/path4" component={zForm}></Route>

                </div>
            </Router>
        </MuiThemeProvider>
    );
  }
}

HealthForm

 class HealthForm extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            jarvisURL: '',
            jarvisURLError: '',
            status: '',
            showStatus: false
        };

        this.handleChange = this.handleChange.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
    }

    validate = () => {
    //…checks for input errors
               }

    handleChange(event) {
        this.setState({
            [event.target.name]: event.target.value
        });
    }

    handleSubmit(event) {
        event.preventDefault();
        const err = this.validate();
        let that = this;
        if (!err) {
                           this.setState({
                jarvisURLError: ''
            });
            console.log(this.state);
            var data = this.state.jarvisURL

            //… a fetch API call
        }
    }

    render() {
            return (
                <form>  
                <TextField
                  ...
                />
                <br/>

                 <Button variant="contained" size="small" color="primary" onClick={e => this.handleSubmit(e)} >
                    Check
                </Button>
                <br />  <br /> 

                  ...

                </form>  
            );
    }


}
export default HealthForm;

EDIT Decided to do the suggestion from Grim

However the saga continues here with another problem: react page refreshes

like image 647
Dendin Avatar asked Apr 29 '26 09:04

Dendin


2 Answers

It is correct that horizontally flowing data is frowned upon, but the reality is that in complex applications its often unavoidable. This is exactly why React provides the Context API. You start by creating a context for the Jarvis data:

import React from "react";
export const JarvisContext = React.createContext();

export class JarvisProvider extends React.Component {

    constructor(props) {
        super(props);

        this.state = {
            url: null,
            setUrl: this.setUrl
        };
    }

    render() {
        return (
            <JarvisContext.Provider value={this.state}>
                {this.props.children}
            </JarvisContext.Provider>
        );
    }

    setUrl = (url) => {
        this.setState({url});
    }
}

Then anytime you need to access the Jarvis state (either setting or getting it) you use the Context.Consumer which passes the current state (which can include setter methods).

First you need to wrap any code that might use the JarvisContext.Consumer in the JarvisProvider. Note that you can also pass props to the provider to set the initial state. I often do this globally in the App.js component, but you can put it anywhere you need it.

<JarvisProvider>
  <HealthForm />
</JarvisProvider>

Then consume it in the HealthForm render method:

render() {
        return (
            <JarvisContext.Consumer>
                {({url, setUrl}) => {
                    <form>
                      <input type="text" value={url} onChange={(e) => setUrl(e.target.value)} />
                    </form>
                }}
            </JarvisContext.Consumer>
        );
    }

Note that this is not an exact copy of your functionality, but should be a good starting point. Saludos!

like image 101
ForrestLyman Avatar answered May 04 '26 04:05

ForrestLyman


So there are a couple ways of doing this. The recommended method would be either the Context API or Redux. However there are some times where this can't be used in an Enterprise environment (I've worked places where Redux is used as an API cache and not used to store data set within the application). Another solution, albeit not best practices, is event bubbling.

With event bubbling you can pass a function as a property to the child component which then bubbles up to the parent component. This is done for several components such as the MaterialUI Button where you pass in a onClick listener. Using your handleClick function you would have something like:

handleSubmit(event) {
    event.preventDefault();
    const err = this.validate();
    let that = this;
    if (!err) {
        this.setState({
            jarvisURLError: ''
        });
        console.log(this.state);
        var data = this.state.jarvisURL

        //… a fetch API call

        this.props.jarvisURLUpdated(this.state.jarvisURL);
    }
}

Where jarvisURLUpdated is a function that calls the parent function and you can set the state of the parent as needed. The parent can then pass in the URL to the desired children.

Another option is the usage of local storage or cookies to store the URL in the browser and reuse (also not recommended by convention). This tends to work a bit better than event bubbling if you're using something like react-router-dom and displaying the information on separate pages (Redux would eliminate the event bubbling issue due to a global state).

like image 36
Grim1101 Avatar answered May 04 '26 04:05

Grim1101



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!