Home > Software engineering >  Passing state from parent component to child function
Passing state from parent component to child function

Time:09-21

I am a bit lost when it comes to passing a state from a component to a function. I have successfully passed a state from Home into ListHome(A component being imported and rendered into Home) but I am struggling to continue passing it to a function that is being rendered in ListHome(Slider). Mainly due to it being a function.

I have looked over the docs again but am still struggling to understand how this should work. A direct edit/example would be super helpful!

I am rendering Home in a stack in App.js. If you wish for me to include this file just let me know.

I appreciate any insight at all more than you know.

Home.js

export default class Home extends React.Component {
 
  constructor(props) {
    super(props)
    this.state ={
      visible: true,
      whichComponentToShow: 'Screen1'
    };
}

goToMap = () => {
  this.setState({whichComponentToShow: 'Screen2'})
}
goToList = () => {
  this.setState({whichComponentToShow: 'Screen1'})
}

  render(){
     if(this.state.whichComponentToShow === 'Screen1'){
      return(
       <View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
        <ListHome
          renderMap = {this.goToMap.bind(this)}
          renderList = {this.goToList.bind(this)}
        />

ListHome.js

export default class ListHome extends React.Component {
  
  goToMap = () => {
    this.props.renderMap();
  }

  goToList = () => {
    this.props.renderList();
  }

render() {
  return (

     <Slider
         renderMap = {this.goToMap.bind(this)}
         renderList = {this.goToList.bind(this)}
     />

Slider.js(I have not implemented anything into this file in attempt to pass the state yet)

const Slider = (props) => {
  
  const [active, setActive] = useState(false)
  let transformX = useRef(new Animated.Value(0)).current;

  //animation code I removed that uses the above const and let


  return (
    //code I removed that just creates a button. 
    //The touchable opacity is how I want to use the state.
    <TouchableOpacity onPress={() => this.goToMap}>

    </TouchableOpacity>
  );
}


export default Slider

CodePudding user response:

Your state and state-setting callbacks are defined as class methods in the Home class component. You can access them with this.goToMap and this.goToList and pass them into ListHome as component props.

In the ListHome class component you can access each with this.props.renderMap and this.props.renderList because that is what the props are named.

In the Slider function component you can access each with props.renderMap and props.renderList because that is what the props are named (note the lack of this to access props in a function component).

This is commonly referred to as prop-drilling. You are just passing a reference to the original function all the way down from App -> ListHome -> Slider so that it can eventually be executed.

There is no need to re-define this function on the way down. All you are saying is that when there is an onPress/onClick event, execute the function. And the function you want to execute is the one defined in Home.

import "./styles.css";
import React from "react";

export default class Home extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      whichComponentToShow: "Screen1"
    };
  }

  goToMap = () => {
    this.setState({ whichComponentToShow: "Screen2" });
  };
  goToList = () => {
    this.setState({ whichComponentToShow: "Screen1" });
  };

  render() {
    if (this.state.whichComponentToShow === "Screen1") {
      return (
        <div style={{ backgroundColor: "#eee", flex: 1 }}>
          <h1>home - screen 1</h1>
          state:
          <pre>{JSON.stringify(this.state, null, 2)}</pre>
          <ListHome renderMap={this.goToMap} renderList={this.goToList} />
        </div>
      );
    } else {
      return (
        <div style={{ backgroundColor: "pink", flex: 1 }}>
          <h1>home - screen 2</h1>
          state:
          <pre>{JSON.stringify(this.state, null, 2)}</pre>
          <ListHome renderMap={this.goToMap} renderList={this.goToList} />
        </div>
      );
    }
  }
}

class ListHome extends React.Component {
  render() {
    return (
      <div style={{ backgroundColor: "#ddd", flex: 1 }}>
        <h2>ListHome</h2>
        ListHome
        <Slider
          renderMap={this.props.renderMap}
          renderList={this.props.renderList}
        />
      </div>
    );
  }
}

const Slider = (props) => {
  return (
    <div style={{ backgroundColor: "#ccc", flex: 1 }}>
      <h3>Slider</h3>
      <button onClick={props.renderMap}>Map</button>
      <button onClick={props.renderList}>List</button>
    </div>
  );
};

Edit friendly-pine-3j7x2

CodePudding user response:

You can drill the props to the component, I have rewritten the code with functional components. It is not tested.

export default function Home() {
  const [visible, setVisible] = useState(true);
  const [componentToShow, setComponentToShow] = useState('Screen1');

  const goToMap = () => {
  setComponentToShow('Screen2')
}
 const goToList = () => {
  setComponentToShow('Screen1')
}

  return(
     { (whichComponentToShow === 'Screen1') ? (
       <View style={{backgroundColor: '#d1cfcf' ,flex: 1}}>
        <ListHome
          renderMap = {goToMap}
          renderList = {goToList}
        />)
:<></>
     })

export default function ListHome({renderMap, renderList}) {
  
  return (

     <Slider
         renderMap= {renderMap}
         renderList = {renderList}
     />
)

const Slider = ({renderMap, renderList}) => { // you have them here
  
  const [active, setActive] = useState(false)
  let transformX = useRef(new Animated.Value(0)).current;

  //animation code I removed that uses the above const and let


  return (
    //code I removed that just creates a button. 
    //The touchable opacity is how I want to use the state.
    <TouchableOpacity onPress={renderMap}>

    </TouchableOpacity>
  );
}


  • Related