This may seem kind of basic but I'm just learning how to use React. Currently what I have going is when I type in the input field and submit, the system console logs my 'search' input. What I'm trying to do is pass my 'search' data from my child component to the parent. Looking for any tips or leads to the right direction.
This is what I have for my child component:
export default class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
onChange = event => {
this.setState({ search: event.target.value });
};
onSubmit = event => {
const { search } = this.state;
event.preventDefault();
console.log(search);
};
render() {
return (
<div className='search-bar'>
<form onSubmit={this.onSubmit}>
<input
className='search'
type='text'
placeholder='Search'
onChange={this.onChange}
search={this.props.search}
value={this.state.searchinput}
parentCallback={this.onChange}
></input>
</form>
<FontAwesomeIcon className='search-icon' icon={faSearch} />
</div>
);
}
}
And in my Parent component (nothing much at the moment)
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
searchUpdate = search => {
console.log(search);
};
render() {
console.log(this.props.search);
return (
<div className='container'>
<SearchBar/>
</div>
);
}
}
Generally to pass data from child component to Parent Component, you can pass a reference of a function as props to child component from parent component and call that passed function from child component with data.
You can do something like this:
export default class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
onChange = event => {
this.setState({ search: event.target.value });
};
onSubmit = event => {
const { search } = this.state;
event.preventDefault();
console.log(search);
this.props.passSearchData(search);
};
render() {
return (
<div className='search-bar'>
<form onSubmit={this.onSubmit}>
<input
className='search'
type='text'
placeholder='Search'
onChange={this.onChange}
search={this.props.search}
value={this.state.searchinput}
parentCallback={this.onChange}
></input>
</form>
<FontAwesomeIcon className='search-icon' icon={faSearch} />
</div>
);
}
In parent component:
export default class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ''
};
}
searchUpdate = search => {
console.log(search);
this.setState({ ...state, search: search })
};
render() {
console.log(this.props.search);
return (
<div className='container'>
<SearchBar passSearchData={this.searchUpdate} />
</div>
);
}
The simplest way would be to pass a function from parent to child:
// in parent component
const setSearchValue = (search) => {
// setState to search
this.setState({search});
}
render (){
return <>
<SearchBar onsearch={this.setSearchValue} />
</>
}
// in child component
// change your searchUpdate
searchUpdate = () => {
const {onsearch} = this.state;
// function call to pass data to parent
this.props.onsearch(onsearch)
}
Just have a function that is passed as a prop to the child component. Let child component do the handle change part and pass the value back to the parent and then do whatever you want to with the value
Code sandbox: https://codesandbox.io/s/react-basic-example-vj3vl
Parent
import React from "react";
import Search from "./Search";
export default class Parent extends React.Component {
searchUpdate = search => {
console.log("in parent", search);
};
render() {
console.log(this.props.search);
return (
<div className="container">
<Search handleSearch={this.searchUpdate} />
</div>
);
}
}
Child
import React from "react";
export default class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
search: ""
};
}
onChange = event => {
this.setState({ search: event.target.value }, () => {
console.log("in child", this.state.search);
this.props.handleSearch(this.state.search);
});
};
onSubmit = event => {
const { search } = this.state;
event.preventDefault();
console.log(search);
};
render() {
return (
<div className="search-bar">
<form onSubmit={this.onSubmit}>
<input
className="search"
type="text"
placeholder="Search"
onChange={this.onChange}
search={this.props.search}
value={this.state.searchinput}
/>
</form>
</div>
);
}
}
Related
I'm trying to send a form-submission handler to a child element through props. Everything renders, but when I click the submit button, I get no alert (see alert('Hi') in the handleSubmit function), and I also don't see the elements of SearchResults change. Instead, the whole page reloads and I'm back in the initial state. What is wrong?
Searcher.js:
class Searcher extends React.Component {
constructor(props) {
super(props);
this.state = {
results: [
{name:'1', key:0},
{name:'2', key:1}
]
};
}
handleSubmit = (event) => {
alert('Hi');
this.setState({
results: [
{name: 'hi', key: 0},
{name: 'again', key: 1}
]
})
event.preventDefault();
}
render() {
return (
<div>
<SearchForm/>
<SearchResults results={this.state.results} handleSubmit={this.handleSubmit}/>
</div>
)
}
}
export default Searcher;
SearchForm.js:
class SearchForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) { this.setState({value: event.target.value}); }
render() {
return (
<form onSubmit={this.props.handleSubmit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<input type="submit" value="Submit" />
</form>
);
}
}
export default SearchForm;
SearchResults.js:
class SearchResults extends React.Component {
render() {
return (
this.props.results.map((result) => (<div key={result.key}>{result.name}</div>))
)
}
}
export default SearchResults;
Passing handeSubmit as props in <SearchForm /> in Searcher.js
render() {
return (
<div>
<SearchForm handleSubmit={this.handleSubmit}/> // Pass Handle Submit
<SearchResults results={this.state.results} /> // I don't see handleSubmit being used in SearchResults
</div>
)
}
Try passing handleSubmit to SearchForm or its value will be undefined
class Searcher extends React.Component {
...
handleSubmit = (event) => {
alert('Hi');
...
}
render() {
return <SearchForm handleSubmit={this.handleSubmit}/>
}
}
export default Searcher;
I am not able to pass the value from the child to parent component. I am new to react please guide me.
This is Greeting component -
/* eslint-disable react/prop-types */
import React from "react";
const Greeting = props => {
const isLoggedIn = props.isLoggedIn;
const name = props.name;
if (isLoggedIn) {
return <h1> Welcome Back {name}</h1>;
} else {
return <LoginInfo name={name} onChange={props.onChange} />;
}
};
function LoginInfo(props) {
return (
<div>
<h1> Please Login</h1>
<input type="text" value={props.name} onChange={props.onChange} />
</div>
);
}
export default Greeting;
This is login component -
import React, { Component } from "react";
import Greeting from "./Greeting";
import LogoutButton from "./LogoutButton";
import LoginButton from "./LoginButton";
class Login extends Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {
isLoggedIn: false,
name: ""
};
}
handleLoginClick() {
this.setState({ isLoggedIn: true });
}
handleLogoutClick() {
this.setState({ isLoggedIn: false });
}
onChange = e => {
this.setState({
name: e.target.value
});
};
render() {
const isLoggedIn = this.state.isLoggedIn;
const name = this.state.name;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting
isLoggedIn={isLoggedIn}
name={name}
onChange={this.onChange}
/>
{button}
</div>
);
}
}
export default Login;
I am using in my app.
<Login />
In greeting component How whatever user entered i can store in state and display in welcome back line with name.
I think you need to maintain state in your parent component and emit change event from child component and change state in parent.
like
In login component
nameChange = (e) => {
this.setState({
name: e.target.value
})
}
<Greeting isLoggedIn={isLoggedIn} name={this.state.name} nameChange={this.nameChange}/>
and in child
<input
type="text"
name="name"
value={this.props.name}
onChange={this.props.nameChange}
/>
So this is how I would refactor your code for the LogInInfo component to pass the values of the user to your LogIn component
First of all you need a state in LogInInfo since you want to store the values of the user, you will use the state for that
/* eslint-disable react/prop-types */
import React from "react";
const Greeting = props => {
const isLoggedIn = props.isLoggedIn;
if (isLoggedIn) {
return <h1> Welcome Back</h1>;
} else {
return <LoginInfo submitForm={props.handleSubmitForm}/>;
}
};
class LoginInfo extends React.Component {
constructor(props) {
this.state = {
name: ""
}
}
handleChange = (event) => {
this.setState({ name: event.target.value })
}
render(){
return (
<div>
<h1> Please Login</h1>
// e is the event that is passed automatically to the function in onSubmit
<form onSubmit={e => this.props.submitForm(e, this.state.name)}>
<input
type="text"
name="name"
value={name}
onChange={this.handleChange}
/>
<input type="submit" />
</form>
</div>
);
}
}
export default Greeting;
At this point you have the value you want to pass to the parent component LogIn to pass this value up, you need a function in your parent component that would get this value for you and pass it to the child component so it can be used, we will do this via props. We also need a variable in the parent's state that will store this value
import React, { Component } from "react";
import Greeting from "./Greeting";
import LogoutButton from "./LogoutButton";
import LoginButton from "./LoginButton";
class Login extends Component {
constructor(props) {
super(props);
this.handleLoginClick = this.handleLoginClick.bind(this);
this.handleLogoutClick = this.handleLogoutClick.bind(this);
this.state = {
isLoggedIn: false,
username: ""
};
}
handleLoginClick() {
this.setState({ isLoggedIn: true });
}
handleLogoutClick() {
this.setState({ isLoggedIn: false });
}
// when you use arrow functions they automatically bind to your component
handleSubmitForm = (e, value) => {
// the following line prevents the page from refreshing when you submit any form
e.preventDefault()
this.setState({ username: value })
}
render() {
const isLoggedIn = this.state.isLoggedIn;
let button;
if (isLoggedIn) {
button = <LogoutButton onClick={this.handleLogoutClick} />;
} else {
button = <LoginButton onClick={this.handleLoginClick} />;
}
return (
<div>
<Greeting isLoggedIn={isLoggedIn} submitForm={this.submitForm}/>
{button}
</div>
);
}
}
export default Login;
when you click the submit button it should update the state in the LogIn component. Hope this helps
You need to do 2 things:
create a function which will handle changes of the input in Login component, send it to Greeting and then to LoginInfo. the function would look something like:
onChange = (event) => this.setState({event.target.name: event.target.value})
note: event.target.name equals to name prop of input. the function above will work only if the name of the state that stores that input value equals to the input name, in your case name.
send the state that stores the value of the input to the LoginInfo. the input element should look like this:
<input type="text" name="name" value={valueFromLogin} onChange={props.onChangeFromLogin} />
I'm trying to call a simple method from the grandparent component in my child component but from some reason I can't , I tried every possible way but I think I'm missing something
here's the full code :
import React, { Component } from 'react';
import './App.css';
var todos = [
{
title: "Example2",
completed: true
}
]
const TodoItem = (props) => {
return (
<li
className={props.completed ? "completed" : "uncompleted"}
key={props.index} onClick={props.handleChangeStatus}
>
{props.title}
</li>
);
}
class TodoList extends Component {
constructor(props) {
super(props);
}
render () {
return (
<ul>
{this.props.todosItems.map((item , index) => (
<TodoItem key={index} {...item} {...this.props} handleChangeStatus={this.props.handleChangeStatus} />
))}
</ul>
);
}
}
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos ,
text :""
}
this.handleTextChange = this.handleTextChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChangeStatus = this.handleChangeStatus(this);
}
handleTextChange(e) {
this.setState({
text: e.target.value
});
}
handleChangeStatus(){
console.log("hello");
}
handleSubmit(e) {
e.preventDefault();
const newItem = {
title : this.state.text ,
completed : false
}
this.setState((prevState) => ({
todos : prevState.todos.concat(newItem),
text : ""
}))
}
render() {
return (
<div className="App">
<h1>Todos </h1>
<div>
<form onSubmit={this.handleSubmit}>
< input type="text" onChange={this.handleTextChange} value={this.state.text}/>
</form>
</div>
<div>
<TodoList handleChangeStatus={this.handleChangeStatus} todosItems={this.state.todos} />
</div>
<button type="button">asdsadas</button>
</div>
);
}
}
export default App;
The method im trying to use is handleChangeStatus() from the App component in the TodoItem component
Thank you all for your help
This line is wrong:
this.handleChangeStatus = this.handleChangeStatus(this);
//Change to this and it works
this.handleChangeStatus = this.handleChangeStatus.bind(this);
Iam trying to do two way binding in react.where if we change any value in parent or child, it should reflect in another component. Since it is getting error while passing the input value. please help.
parent
export default class Header extends Component {
constructor() {
super();
this.state = {
value: "sample"
};
}
updated(changeValue) {
this.setState({
value: changeValue
})
}
render() {
return (
<div>
<h1>{this.state.value} </h1>
<App value={this.state.value} update={this.updated.bind(this)} />
</div>
);
}
}
child :
class App extends Component {
update(event) {
var changeValue = event.target.value;
this.props.update(changeValue);
}
render() {
return (
<div>
<input type="text" value={this.props.value} onChange={this.update.bind(this)} />
</div>
);
}
}
I'm using redux-form and formValueSelector to get input values from fields. I want to get value on change, but ##redux-form/CHANGE action is called after my function called on onChange. So I get not updated value. My code:
export class PersonFilter extends React.Component {
constructor(props) {
super(props);
}
filterByName = (event, searchName) => {
//here searchName is getting old value
store.dispatch({type: 'PERSON_FILTER_BY_NAME', payload: {name: searchName}});
};
render() {
const {
searchName
} = this.props;
return (
<form className="person person--filter" onSubmit={e => {
e.preventDefault();
this.filterByName(e, searchName)
}}>
<Field
onChange={e => {
this.filterByName(e, searchName)
}}
className="person__input" icon="search"
name="searchName" component={renderField} type="text"
placeholder="Name"/>
</form>
);
}
}
PersonFilter = reduxForm({
form: 'filter',
initialValues: {
searchName: store.getState().personsFilterReducer.filterByName
}
})(PersonFilter);
const selector = formValueSelector('filter');
PersonFilter = connect(state => {
const searchName = selector(state, 'searchName');
return {
searchName
}
})(PersonFilter);
and wrapper component:
class Persons extends React.Component {
constructor() {
super();
}
render() {
return (
<div>
<PersonFilter/>
</div>
};
}
}
Instead of just passing onChange to the action you should setState, firstly initialise the state this.state inside the wrapper component constructor and make sure you pass props to the constructor as well , and then setting a state inside onChange function this.setState and binding it.
Something like this:
Wrapper Component
class Persons extends React.Component {
constructor (props) {
super(props);
this.state = {}
}
onChange(field, value) {
this.setState({[field]: value});
}
render () {
return <PersonFilter onChange={this.onChange.bind(this)} />
}
}
And inside your PersonFilter component make a function onFieldChange which will pass the reference to the function onChange inside wrapper component to set the state this.setState
export class PersonFilter extends React.Component {
constructor(props) {
super(props);
}
onFieldChange(event) {
const changeName = event.target.name;
const changeValue = event.target.value;
this.props.onChange(fieldName, fieldValue);
}
and then finally
<Field
onChange={this.onFieldChange.bind(this)}
className="person__input" icon="search"
name="searchName" component={renderField} type="text"
placeholder="Name"/>