Reputation: 15
I'm currently creating a search bar where App
is the parent and Header
, Home
are the children. I'm trying to pass the input from Header
to Home
via App
but it seems that when I try to load in {this.state.searchValue}
it does nothing.
I'm lost of where I am wrong in my code. I'm also using Route
to route the props from Header
to Home
.
Here is my code:
Header.js (Child 1)
class Header extends Component {
constructor(props) {
super(props);
this.state = {
search: "",
};
}
onChange = (event) => {
this.setState({ search: event.target.value });
};
submitSearch = (event) => {
event.preventDefault();
console.log(this.state.search);
this.props.passSearchData(this.state.search);
};
render() {
return (
<React.Fragment>
<nav className="navbar navbar-expand-lg navbar-light bg-light">
<form className="form-inline">
<input
className="form-control mr-sm-2"
type="text"
placeholder="Search"
onChange={this.onChange}
/>
<button
className="btn btn-danger"
type="submit"
onClick={this.submitSearch}
>
Search
</button>
</form>
</nav>
</React.Fragment>
);
}
}
export default Header;
App.js (Parent)
class App extends Component {
constructor() {
super();
this.state = {
searchValue: "",
};
}
handleSearchData = (search) => {
this.setState({ searchValue: search });
};
componentDidMount() {
this.props.getItems();
}
render() {
return (
<div className="App">
<Router>
<Header passSearchData={this.handleSearchData} />
<Route
exact
path="/"
render={(props) => (
<Home {...props} searchValue={this.state.searchValue} />
)}
/>
</Router>
<Footer />
</div>
);
}
}
Home.js
class Catalog extends Component {
constructor(props) {
super(props);
this.state = {
};
}
render() {
return (
<div>
<p>{this.props.searchValue}</p>
</div>
);
}
}
Upvotes: 0
Views: 1088
Reputation: 543
I think using react context better for this problem, because passing state between routes quite painful
First u declare your own Provider to act as intermediary between components.
The context will save all the application state. and to consume at your components, simply use useContext
and pass the Context u want to use, at this useCase, i call it AppContext
. by using the same context, your components get the same state and trigger update immediately
The solution i provide is using functional component. If u are using class Component, just simply create a functional component, then pass the context to the class component
import React, { useContext, useState } from 'react'
const AppContext = React.createContext({})
const AppProvider = props => {
const [currentState, setCurrentState] = useState(null)
const handleState = value => {
setCurrentState(value)
}
const contextValue = { handleState, currentState }
return (
<AppContext.Provider value={contextValue}>
{props.children}
</AppContext.Provider>
)
}
const Child1 = props => {
const { handleState } = useContext(AppContext)
const handleClick = e => {
handleState(e.target.values)
}
return (
<button onClick={handleClick}>Change State</button>
)
}
const Child2 = props => {
const { currentState } = useContext(AppContext)
return (
<h1>{currentState}</h1>
)
}
const Parent = props => {
return (
<Router>
<AppProvider>
<Route component={Child1} />
<Route component={Child2} />
</AppProvider>
</Router>
)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Upvotes: 1