Passing props/state to/from parent component - javascript

So I have a parent component and a log in component.
I want the user to enter their details and then hit submit and then store/pass those details around so they can be used by other components.
how is this best done in React?
for example I have this input field inside my log in component
<p>
<input type="text" id="playerName" value={this.props.nameValue} onChange={this.props.handleNameChange}/>
</p>
Then I want to pass the value that is entered to the parent component
I have this function in my parent component:
handleNameChange(event){
this.setState({nameValue: event.target.value})
};
and in my return I have:
return (
<div>
<LoginPage handleClick={this.handleClick.bind(this)} handleNameChange={this.handleNameChange.bind(this)}/>
</div>
)
However, when I console.log(nameValue) I get undefined. any ideas? can add more code if necessary/relevant

From your example you never pass nameValue to the child component.
Updated your example of rendering the LoginPage, passing this.state.nameValue into the child component via props:
return (
<div>
<LoginPage
handleClick={this.handleClick.bind(this)}
handleNameChange={this.handleNameChange.bind(this)}
nameValue={this.state.nameValue}
/>
</div>
)

Your approach using state and props is fine. Are you sure that you shouldn't just be using...
console.log(this.state.nameValue);
This is a working example
class Parent extends React.Component {
constructor() {
super();
this.state = {
nameValue:''
};
}
render() {
return (
<Child handleClick={this.handleClick.bind(this)} handleNameChange={this.handleNameChange.bind(this)} nameValue={this.state.nameValue} />
);
}
handleNameChange(e) {
this.setState({
nameValue: e.target.value
});
}
handleClick() {
alert(this.state.nameValue);
}
}
class Child extends React.Component {
render() {
return (
<div>
<input type="text" value={this.props.nameValue} onChange={this.props.handleNameChange} />
<button onClick={this.props.handleClick}>Click Me!</button>
</div>
);
}
}
JSFiddle here.

Related

React : Pass conditional renderings data

Assuming that this is a Toggle component to hide and display data, when called alone it's working perfectly.
Now I have a dashboard.js where I will be calling this component, but I only want to output the data, keeping the toggle switch separated in his file.
How do I pass data from the Toggle component to the Dashboard component ?
Still newbie in React and from what I learned apparently you can't pass data from child to parent.
import React, { Component } from 'react';
export default class Toggle extends React.Component{
constructor(){
super();
this.state={isShowBody: false}
}
handleClick(event) {
this.setState({isShowBody: !this.state.isShowBody})
}
render() {
return (
<div >
<div >
<span className="switch switch-sm" >
<label>
<input type="checkbox" name="select" onClick={this.handleClick.bind(this)}/>
<span />
</label>
</span>
</div>
{this.state.isShowBody ?
<div>
Data test
</div>
: null}
</div>
);
}
}
This might give you more insight in addition to what the previous answer is: Using Redux would definitely a good option but that entirely depends on the complexity of the project.
export class Toggle extends React.Component {
constructor(){
super();
this.state={
isShowBody: false
}
}
handleClick = (event) => {
this.setState({ isShowBody: !this.state.isShowBody })
}
checkbox = () => {
return (
<span className="switch switch-sm" >
<label>
<input type="checkbox" name="select" onClick={() => this.handleClick(this)}/>
</label>
</span>
)
}
dataTest = () => {
return (
<div>
Data test
</div>
)
}
render() {
return (
<div>
{this.checkbox()}
{this.state.isShowBody && this.dataTest()}
/**
* You can extract this dataSet into another component as well where you can pass initial visibility value as this.state.isShowBody
* for example
* <Dataset visibility={this.state.isShowBody} />
* */
</div>
);
}
}
If you want the parent to have information the child has you need to left up the state to the parent component and pass it to the child.
If your component has the potential to become bigger, keeping lifting up the state will become a problem so consider using a state management library like Redux.

(ReactJS) Function not passing to child component

I am trying to pass props and functions from a parent to a child component in React. However, when I try to call the function in the child component, I receive the error: "Uncaught TypeError: Cannot read property 'bind' of undefined".
This would suggest that the function created in the parent element is not being accessed by the child component. Am I missing a step in my code that would allow me to reference a parent component function from a child component?
I am defining states as props in my parent component, for use in conditional rendering in my child component. I am also defining functions in the parent component, which I am trying to call in my child component.
Provided below is my code:
Note: The flow is supposed to work as follows: Click Sign Up button > Call SignUpClick function > render "SignUp" component (based on the conditional rendering logic outlined in the child component)
The same flow concept would apply if someone clicked the Sign In button.
Parent Component
export default class Parent extends Component{
constructor(props) {
super(props);
this.state = {
SignUpClicked: false,
SignInClicked: false,
};
this.SignUpClick = this.SignUpClick.bind(this);
this.SignInClick = this.SignInClick.bind(this);
}
SignUpClick() {
this.setState({
SignUpClicked: true,
});
}
SignInClick() {
this.setState({
SignInClicked: true,
});
}
render () {
return (
<div>
<Child />
</div>
)
}
}
Child Component
export default class Child extends Component {
render () {
if (this.props.SignUpClicked) {
return(
<SignUp />
) } else if (this.props.SignInClicked) {
return (
<SignIn />
)
} else {
return (
<div>
<div>
<Button onClick={this.SignUpClick.bind(this)}> Sign Up </Button>
</div>
<div>
<Button onClick={this.SignInClick.bind(this)}>Sign In</Button>
</div>
</div>
)
}
}
}
Change the render method in parent class to pass SignUpClick and SignInClick to child.
return (
<div>
<Child SignInClick={this.SignInClick} SignUpClick={this.SignUpClick}/>
</div>
)
Also, in the child class, access the methods as this.props.SignUpClick and this.props.SignInClick
If you think about it, where would the child component grab the references for those functions ? The parent needs to give the child access to those methods, and how does a parent pass data to a child, with props! In your case you are not passing any prop at all to the child, so here is how your parent render method should look like:
render () {
return (
<div>
<Child
signUpClicked={this.state.SignUpClicked}
signInClicked={this.state.SignInClicked}
onSignUpClick={this.onSignUpClick}
onSignInClick={this.onSignInClick}
/>
</div>
);
}
This is how a parent communicates with a child passing down props that are now accessible with this.props. At this point your Child component render method would look like this:
render () {
const {
signUpClicked,
signInClicked,
onSignUpClick,
onSignInClick,
} = this.props;
if (signUpClicked) {
return(<SignUp />);
} else if (signInClicked) {
return (<SignIn />);
} else {
return (
<div>
<Button onClick={onSignUpClick}> Sign Up </Button>
<Button onClick={onSignInClick}>Sign In</Button>
</div>
)
}
}
I used destructuring to help with readability. Hope this helps!

React / Redux - focus input field of Component 1 by click on button in Component 2

I asked a question on here earlier, but I think I should have been more specific. Say I have two components, which I call from a higher order component:
So my higher order component, containing these components, looks like this (or at least its render method):
<div>
<Navigation />
<View />
</div>
Now, Navigation /> contains a button. Whenever that button is clicked, I want to set the focus on an input field, which is in <View />.
If both things were in the very same component, I learned that I would do something like this:
<button onClick={() => {this.myInp.focus()}}>Focus Input</button>
<input type="text" ref={(ip) => this.myInp = ip} />
I am using Redux by the way, if this should make a difference.
Since they are descendants of the same element you can use a state element and function to change that state element in the parent div and pass down as props to View and Navigation.
constructor(){
super()
this.state = {
inputFocus:false;
}
this.setInputFocus = this.setInputFocus.bind(this)
}
setInputFocus(value){
this.setState({inputFocus:false});
}
Then in the render method of the div just pass them down as props
<div>
<Navigation setInputFocus={this.setInputFocus}/>
<View inputFocus={this.state.inputFocus}/>
</div>
In the Navigation
<button onClick={() => {this.props.setInputFocus(true)}}>Focus Input</button>
and in the View
<input type="text" ref={(ip) => this.myInp = ip}/>
and have this in the componentWillReceiveProps which detects when props change and runs actions then.
componentWillReceiveProps(nextProps){
if(nextProps.inputFocus)
this.myInp.focus()
}
So when the inputFocus changes in the parent it will fire the componentWillReceiveProps in the View element and focus the input.
Along with the refs, this problems also involves child to parent and parent to child interaction.
So what I am doing in the below snippet is form the Navigation component, I have to call the parent component since a component can't directly have access to its siblings. From the parent you can get access to the child component through refs and in turn you can also access the refs which are defined in the child component
See the snippet below
class App extends React.Component {
focusInput = () => {
this.myView.myInput.focus()
}
render() {
return (
<div>
<Navigation focusInput={this.focusInput}/>
<View ref={(view) => {this.myView = view}}/>
</div>
)
}
}
class Navigation extends React.Component {
render() {
return (
<button onClick={() => this.props.focusInput()}>Focus</button>
)
}
}
class View extends React.Component {
render() {
return (
<input type="text" ref={(ip) => this.myInput = ip}/>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>
In case you have multiple buttons in navigation thorugh which you want to focus multiple different inputs, you can do so in the following manner
class App extends React.Component {
focusInput = (ip) => {
this.myView[ip].focus()
}
render() {
return (
<div>
<Navigation focusInput={(val) => this.focusInput(val)}/>
<View ref={(view) => {this.myView = view}}/>
</div>
)
}
}
class Navigation extends React.Component {
render() {
return (
<div>
<button onClick={() => this.props.focusInput("myInput1")}>Focus1</button>
<button onClick={() => this.props.focusInput("myInput2")}>Focus2</button>
</div>
)
}
}
class View extends React.Component {
render() {
return (
<div>
<input type="text" ref={(ip) => this.myInput1 = ip}/>
<input type="text" ref={(ip) => this.myInput2 = ip}/>
</div>
)
}
}
ReactDOM.render(<App/>, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="app"></div>

What's the proper way to pass dependencies between components in React?

Imagine that Component A creates a list of items that Component B needs to display. What's the proper way to pass data from Component A to Component B from their parent?
For example, let's say that Component A's constructor creates a list of items and has a function _getListItems() that returns that list. I'm hoping the parent can then pass that list on to other components via props.
My naive (non-working) implementation has their parent attempting to render the components like this:
render () {
return (
<div>
<h1>Data Test</h1>
<ComponentA ref='compa'/>
<ComponentB items={this.refs.compa._getListItems()}/>
</div>
);
}
....although the code above doesn't work, I hope it illustrates what I'm trying to do.
ps. nOOb to react and javascript, so forgive me if the answer to my question's obvious...
Divide your components into two separate categories.
Presentational Component that has responsibility to display a thing. This component should not have state (except for UI state).
Container Component that knows the data.
https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0#.skmxo7vt4
So, in your case the data should created by parent of ComponentA and ComponentB and pass the data to both ComponentA and ComponentB via props.
Example:
render(){
let items = this._getListItems();
return (
<div>
<ComponentA items={items} />
<ComponentB items={items} />
</div>
);
}
Edit
Rewrite OP's approach in the comment:
class MyContainer extends React.Component {
constructor(props) {
super(props);
this.state = { stuff: [1,2,3] };
}
render() {
return (
<div>
<ComponentA items={this.state.stuff} />
<ComponentB items={this.state.stuff} />
</div>
);
}
}
Following the accepted answer above, I've just had a (related) EUREKA moment, so I'm going to expand on the answer; when the parent uses its own state to pass props to its children, whenever the parent's state changes, its render() function is called, thus updating the children with the updated state. So you can do stuff like this:
class MyContainer extends React.Component {
constructor(props) {
super(props);
let sltd = this.props.selected
this.state = {
stuff: [1,2,3],
selected: sltd
};
}
_handleAStuff(value) {
this.setState(selected: value)
//do other stuff with selected...
}
_handleBStuff(value) {
this.setState(selected: value)
//do other stuff with selected...
}
render() {
return (
<div>
<ComponentA items={this.state.stuff} selected={this.state.selected} parentFunc={this._handleAStuff.bind(this)} />
<ComponentB items={this.state.stuff} selected={this.state.selected} parentFunc={this._handleBStuff.bind(this)} />
</div>
);
}
}
MyContainer.defaultProps = {
selected: 0
}
class ComponentA extends React.Component {
constructor(props) {
super(props)
}
_handleSelect(value) {
this.props.parentFunc(value.label)
}
render() {
const itm = this.props.items.map(function(values) {
return { value: values, label: values}
})
return (
<div>
<Select
options={itm}
value={this.props.selected}
onChange={this._handleSelect.bind(this)}
/>
</div>
);
}
}
// ComponentB...
The callback pattern above means that ComponentA and ComponentB do not need to maintain state, they simply 'render stuff', which is also pretty cool. I'm beginning to see the power of REACT...

why I can't get my onChange/onBlur handler work on custom component (reactjs)

Why I can't get my onChange handler work on child custom component? did I miss something. Can you guys help me with solutions, if there's best practice to do this can you tell me.
thanks.
Sample code:
var TextBox = React.createClass ({
getDefaultProps: function() {
return {
className: 'input-box'
};
},
render() {
return (
<input type="text" />
);
}
});
var Dashboard = React.createClass({
handleChange() {
alert('test');
}
render() {
return (
<div>
<h1>Components</h1>
<label>Input Box</label><br/>
<TextBox onBlur={this.handleChange} type="text" placeholder="hints (optional)"/>
</div>
)
}
});
//ReactDOM.render goes here...
You need to pass along the event handlers as props all the way to the input component. As it is, your input has no event bindings setup.
An easy way to ensure all of your props are getting passed down to the innermost child is to use the spread operator to pass all of your props in your TextBox component down to the child.
So, your TextBox component render function would look like:
render() {
return (
<input { ...this.props } type="text" />
);
}
And that's it! All the props you pass to <TextBox /> will make their way to the <input>
You need to use a callback to get the changes in parent component
try as below,
class TextBox extends React.Component {
render() {
return (
<input onBlur={this.props.callBack} type="text" />
);
}
}
class Dashboard extends React.Component {
render() {
const handleChange = () => {
console.log('---');
}
return (
<div>
<h1>Components</h1>
<label>Input Box</label><br/>
<TextBox callBack={handleChange} type="text" placeholder="hints (optional)"/>
</div>
);
}
}
React.render(
<Dashboard />,
document.getElementById('react_example')
);

Categories

Resources