say i have this React Class. This is NOT my main component that I'm rendering. how can i pass the state i set in here UPWARDS to the parent component.
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
playerOneName: ''
}
this.selectPlayerOne = this.selectPlayerOne.bind(this);
}
selectPlayerOne(e, data) {
this.setState({playerOneName: data.value})
}
render() {
let players = [];
this.props.players.map((player) => {
players.push({text: player.name, value: player.name})
})
return (
<div className="playersContainer">
<div className="players">
<Dropdown onChange={this.selectPlayerOne} placeholder='Select Player One' fluid selection options={players} />
</div>
</div>
)
}
}
when I say parent component i mean the class that is going to display player like so:
<Player />
I.e. how can I make this.state.playerOneName available to the parent?
Hey so the point here is that you are basically passing in, from your parent component into your child component, a prop which is a function.
In parent:
handler(newValue){
this.setState({key: newValue})
}
render() {
return(
<Child propName={handler.bind(this)}>
)
}
When a change takes place in your child component, you call the function and pass in the new value as an input. This way you are calling the function in your child component, and making a change to the state of the parent component.
In your case you want to, instead of setting the state of playerOneName, pass in a function from the parent of this class and do something like this.props.functionFromParent(playerOneName) in your 'selectPlayOne' function.
It is true that the flux pattern is unidirectional, however when you're dealing with smart and dumb components you will see that data is passed from a dumb component to a smart component in this way. It is perfectly acceptable React form!
"Lifting state up" for React means that you should replace data from your child component to parent component state and pass data for presentation to child component by props.
You can do something like this to achieve your goal. Create a parent component which hold playerOneName as its state. Pass it as a prop to child component and with that also a function that changes the playerOneName whenever it is changed in the child component.
class Parent extends Component {
constructor(props){
this.state = {
playerOneName: ''
}
}
render() {
return(
<Child
playerOneName={this.state.playerOneName}
onPlayerOneNameChange={(playerOneName) => this.setState({playerOneName})}
/>
);
}
}
Use this function like this in child component to change the name of playerOneName in Parent component, like this your child component is only displaying the value of the playerOneName all the changes are done in Parent component only.
class Child = props => {
const { playerOneName, onPlayerOneNameChange } = props;
return (
<TextInput
value={playerOneName}
onChangeText={(playerOneName) => onPlayerOneNameChange(playerOneName)}
/>
);
}
By this you can use updated playerOneName in your Parent component whenever you like by using this.state.playerOneName
Related
How can I trigger a function that is inside the child component from the parent component doing it in the same style as drawer navigation.
They do it like this: this.props.navigation.toggleDrawer(); from the parent
How can I do the same?
If I understood your question correctly, I think you mixed up thing a bit. The example you are showing is an example for triggering a parent component's function from child.
I'll try to clear things up a bit with 2 examples.
1) Trigger from child:
To trigger a function of a parent component from a child you can just pass the function as a property to the child component and run it when you need it.
class Parent extends React.Component {
someFunction = (text) => {
console.log('Message from child: ', text);
}
render () {
return(
<Child someProperty={this.someFunction} />
)
}
}
class Child extends React.Component {
_onPress = () => {
// check if the property is defined and not null
if(this.props.someProperty) {
// run the function that is passed from the parent
this.props.someProperty();
}
}
render() {
return(
<Button onPress={this._onPress} title="Click Me"/>
)
}
}
2) Trigger from parent:
To trigger a function on a child component from parent, you can pass a property that changes when some action happens on the parent component. This will trigger a re-render (in most cases, for more info please take a look at shouldComponentUpdate) in child component. You can check the property changes and then do what you need to do in child component.
class Parent extends React.Component {
state = {
someParameter: 'someInitialValue',
}
someFunction = (text) => {
this.setState({ someParameter: 'someValue' });
}
render () {
return(
<Child someProperty={this.state.someParameter} />
)
}
}
class Child extends React.Component {
someFunction = (text) => {
console.log('Message from parent: ', text);
}
componentDidUpdate(prevProps, prevState, snapshot) {
// Check if the suplied props is changed
if(prevProps.someProperty !== this.props.someProperty) {
// run the function with the suplied new property
this.someFunction(this.props.someProperty);
}
}
render() {
return(
{/* ... */}
)
}
}
Since you haven't provided any code. Here are my thoughts on the problem.
When you list down a component in a navigator, be it StackNavigator or DrawerNavigator, the component will receive some props provided by the navigation class itself.
There's an option to send more parameters as props to these navigation objects. Among these extra parameters, can be your one method toggleDrawer().
Also, if you parent component is listed in the navigator and the child component is not. You'll need to explicitly pass the navigation props (this.props.navigation) to the child component.
So, when you are inside that child component, all you gotta do is fetch those props and voila, it'll do the needful!
Hope this clarifies out stuff for you.
EDIT --- For your third comment
Assumptions:
Parent component is listed as DrawerNavigator({ParentScreen: {screen: ParentScreen}})
There is a <Route/> component in ParentScreen.
So, what you can do is pass the default navigation props to the <Route> component.
Like - <Route navigation={this.props.navigation} /> and in child component, you can trigger this.props.navigation.toggleDrawer() on any onPress() event of any element.
class Parent extends React.Component {
parentFunction() {
this.refs.chid.childFunction(parameterToPassed);
}
render () {
return(
{/* ... */}
<Child ref='child' />
{/* ... */}
)
}
}
class Child extends React.Component {
childFunction(text){
console.log('parameter Passed from parent: ', text);
}
render() {
return(
{/* ... */}
)
}
}
Function named as childFunction is declared in child component. and called in parent component, inside the function parentFunction.
for more information Call child function from parent component in React Native
I have 3 components, that is 2 child components and one parent component.
I wanted to pass the child component value to parent (only the values not the components enitirely,it should not visible in parent) and this values from parent to another child component.
Any suggestions or logic of how to proceed on this, since I don't have any guidance as of right now I had to ask here. Is the above problem possible.
The code is very complex, so I have not put here.
Thank you
When you say values, do you mean state, props, user input, something else?
If you mean state or props: React has a 1-way data flow, so the easiest way to accomplish this is to actually store the data at a higher level. Either store the data used by the child in the parent and pass it down to the children for consumption, or else use a store that both parent and children have access to. Either way, this will make it much easier for all components to access the data.
If you mean user input: one way you can accomplish this is to pass a callback from the parent component to the child as a prop, and then in the child call that callback when a user does something or changes some value. The callback function can make the data accessible to the parent on that user action, and then you can decide what to do with the data from there.
AksharaDL,
Child to Parent — Use a callback and states
Parent to Child — Use Prop
Also here is another article explaining it: https://medium.com/#ruthmpardee/passing-data-between-react-components-103ad82ebd17
here is the solution.
in parrent component you have a state. and have a setData method to update state. pass setData to ChildOne use props. and data to ChilTwo and use it
class StoreBanner extends React.Component {
constructor() {
this.state = {
data: 'whatever'
}
}
setData = (data) => {
this.setState({data})
}
render() {
return (
<div>
<ChildOne setData={this.setData}/>
<ChildTwo data={this.state.data}/>
</div>
)
}
}
and in ChildOne you can update the parrent state
class ChildOne extends React.Component {
setParentData = () => {
this.props.setData('another')
}
...
}
You can do it like this.
class ParentComp extends React.Component {
constructor() {
super();
this.state = {
theStateToPass: null
}
this.receiveDataFromChild = this.receiveDataFromChild.bind(this);
}
receiveDataFromChild(data) {
this.setState({
theStateToPass: data
})
}
render() {
return (
<div>
<FirstChild updateMe={this.receiveDataFromChild} />
<SecondChild stateFromFirstChild={this.state.theStateToPass} />
</div>
)
}
}
class FirstChild extends React.Component {
constructor(props) {
super(props);
this.callParentMethod = this.callParentMethod.bind(this);
}
callParentMethod(e) {
let someDataToSend = "ABC";
this.props.updateMe(someDataToSend)
}
render() {
return (
<div onClick={this.callParentMethod}>
</div>
)
}
}
class SecondChild extends React.Component {
render() {
return (
<div>
{this.props.stateFromFirstChild}
</div>
)
}
}
however it becomes complex and might lead to one's pulling their hair out. so i would suggest using redux , it keeps the flow simple , you have a reducer , actions and a container. everything goes with a flow and keeps it clean but it does comes with an extra overhead of more code as you will be creating container reducer and actions.
I am developing a simple browser app to get some specific data from the user.
I have several components to simplify the proccess of collecting that data, but I am currently rethinking my way of rendering this component.
Basically, i have my main component, which uses state to keep track of which component to render.
I am doing this for almost all of my components.
Also, i also have a function inside the parent component, that i pass to the child component via props, and that is used as a callback to pass the child state to its parent, when that component is no longer useful.
class Main extends React.Component {
constructor(props){
this.state = {
renderA: true,
renderB: false,
childState: null
}
}
collectState(state){
this.setState({
childState: state
});
}
render() {
let content = null;
if(this.state.renderA === true){
content = <ComponentA />
} else {
content = <ComponentB />
}
return(
<div>
{content}
</div>);
}
}
So, using the above example, the child would be something like this
class ComponentA extends React.Component {
constructor(props){
super(props);
this.state = {
stop: false,
usefullInfo: null
}
destroy() {
this.props.collectstate(this.state.usefullInfo)
}
render(){
render something (like a Form) untill this.state.usefullInfo is set;
in that case, set this.state.stop true which will call destroy, passing the usefull information to parent
}
}
So, this method works for me, but i can see clearly that most probably this is not the way to do this.
At this point my question are:
1) how can I stop rendering a component without having to track it with some property like this.state.stop ?
2) if i want to render 2 different components, like in the main component, do I always have to keep a renderA and renderB property on state, to render one or another?
3) is there a better way to pass information from child to parent? i am currently using a callback function passed via props from parent to child, and i am invoking that callback when the component has done its purpose
4) any general suggestions on how to improve the quality of the above code?
Thank you for you help :)!
Your example works fine, but in React it is recommended to lift state up when handling data from multiple children (source). So I would recommend to keep the sate of every children in the parent, and pass props with values and handlers to the children.
Here's a sample app you can check. The form components handle the case you want to implement.
To answer your questions:
The parent component should decide, based on its own state, whether to render a child component or not.
It's not needed to keep variables on state about what component to render. that should be computed in render() based on the parent's state
Yes, callback are the recommended way to pass information to parents
Code quality looks good. You can always do good with tools like prettier or ESlint.
Here's an example:
class Main extends React.Component {
constructor(props) {
this.state = {
stateA: '',
stateB: '',
};
}
handleStateChange(name, value) {
this.setState({
[name]: value,
});
}
render() {
const { stateA, stateB } = this.statel;
const shouldRenderA = !stateA;
if (shouldRenderA) {
return <ComponentA value={stateA} onChange={value => this.handleStateChange('stateA', value)} />;
}
return <ComponentB value={stateA} onChange={value => this.handleStateChange('stateB', value)} />;
}
}
class ComponentA extends React.Component {
render() {
const { value, onChange } = this.props;
return <input type="text" value="value" onChange={onChange} />;
}
}
I am new in react js.
I need to change the whole view on click of button
For this i need to update parent component's state from child component.
Like we do as a session variable. Do you guys have any idea about it then please help me out.
Thanks in advance.
This is my code :
App.jsx
class App extends React.Component {
constructor(props) {
super(props)
}
render() {
let RedirectTo = this.state.page;
let RenderPage;
switch (RedirectTo) {
case 'component':
RenderPage = true && <NextPage />;
break;
default:
RenderPage = true && <Index />;
}
return (
<div>
{RenderPage}
</div>
);
}
Child.jsx
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {redirect: 'yes'};
this.state = {page: 'component'};
}
render() {
if (this.state.redirect === 'yes') {
return (
<div>
{ true && <App /> }
</div>
);
} else {
return (
<div>
<a onClick={this.Validate} href="javascript:void(0);">
Click To Next
</a>
</div>
);
}
}
First, React component working on Parent to child manner not child to parent, whatever function you want to call which can affect your parent from child then you have to pass the props into child and invocation happen through the parent so that will affect your parent as well as child,
What you want to tried to achieve is wrong way you have to introduce the Router in your application which can route the one page to another one you need to check the React-Router for that so basically navigation of one component to another component we can easily achieve using react-router, React-Router
Just make a function in parent like
function () {
// your functionality here
}
then call the child component in parent as
<child functionProp = {this.function} />
In your child component call the function in parent by
this.props.functionProp
In parent you can pass a function as props to the child as:
<child someFunction={this.handleFunction} />
And in handleFunction method in parent you can do whatever you want.
handleFunction(value) {
//do something
}
And in child you can call that someFunction as:
this.props.someFunction(value)
In this way you can communicate to parent through child.
The main idea is that if there are dynamically generated components , how can their props/or state be changed from the parent component. how can the parent know which child component to update.
can i somehow tell the parent component to set the state and pass the value to the correct child component, rather then changing all the child components, the child components will all be similar(clones but each can have different props , state)
this is my basic code and i want to change the state of only 1 span rather then both, i want to apply that idea to components.
class MainApp extends React.Component {
constructor(props){
super(props)
this.ChangeText= this.ChangeText.bind(this)
this.state={
text: "hi"
}
}
ChangeText(e){
this.setState ({
text: "hellow"
})
}
render() {
return (
<div>
<button onClick={this.ChangeText}>Click </button>
<span>{this.state.text}</span>
<span>{this.state.text}</span>
</div>
);
}
}
You'll have to identify each span somehow, it could be based on an index (ie. text1, text2, text3, and so on...) then manage each one separately in the state, the you will have something like:
this.setState({
text1: "hello",
text2: "how are",
text3: "you doing?"
});
And in your render method:
render() {
return (
<div>
<span>{this.state.text1}</span>
<span>{this.state.text2}</span>
<span>{this.state.text3}</span>
</div>
);
}
That same behavior can be used for components, as React will re-render and pass the updated props to any component using the part of the state that you update.