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>
);
};
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>
);
}