Recently I learned how to pass props from one component to another. In my case, from <FileTree> to <TextBox>, as you can see here: https://codesandbox.io/s/y018010qk9
But after, I reorganized the code a bit and now it is possible to see the structure of my React App inside <App> (App.js). I decided to put the <FileTree> and <TextBox> side by side, with Bootstrap.
So, logically I thought that passing props from <App> to <TextBox> would be the same as I did before: From <FileTree> to <TextBox>. Unfortunatelly, it is not the case.
At the moment, this is the code inside <App>:
// Structure of the project
export class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className="col-md-12">
<SearchEngine />
</div>
<div className="col-md-6">
<FileTree />
</div>
<div className="col-md-6">
<TextBox content={this.props.activeNode} />
</div>
</div>
);
}
}
And here, the code inside <TextBox>:
// TextBox component
export class TextBox extends React.Component {
constructor(props) {
super(props);
this.state = {
content: 'Select A Node To See Its Data Structure Here...'
}
this.showContent = this.showContent.bind(this);
}
showContent (newContent) {
this.setState ({
content: newContent
})
}
componentWillReceiveProps (nextProps) {
this.setState ({
content: nextProps.content
})
}
render() {
return (
<div className="padd_top">
<div className="content_box">{this.state.content}</div>
</div>
);
}
}
export default TextBox;
Just in case, here one can find the <FileTree> component:
// Construction of FileTree
export class FileTree extends React.Component {
constructor(props) {
super(props)
this.state = {
activeNode: null
}
this.setActiveNode = this.setActiveNode.bind(this);
}
setActiveNode(name) {
this.setState({activeNode: name})
}
render() {
return(
<div className="padd_top">{
renderTree(
this.props.root || root,
this.setActiveNode,
this.state.activeNode
)
}
</div>
)
}
}
I'm recently getting to know React.js and I'm very thankful for any advice/clarity you can provide.
Thank you.
You need to use lift state method passing state from child to parent then from parent pass it to the child you want
In your parent component create a constructor with states then create liftStateUp function pass it to the child component that you want to receive the data from
constructor(props) {
super(props)
this.state = {
activeNode: '',
}
}
liftStateUp = (data) =>{
this.setState({ activeNode: data})
}
<div>
<div className="col-md-6">
<FileTree liftStateUp={this.liftStateUp} />
</div>
<div className="col-md-6">
<TextBox content={this.state.activeNode} />
</div>
</div>
Then in file_tree.js FileTree function you need to call liftStateUp function that we created it in the parent component
setActiveNode(name) {
this.setState({ activeNode: name });
this.props.liftStateUp(name);
}
https://reactjs.org/docs/lifting-state-up.html
Props are passed down from the parent component to child component. You need to work with global store so that you can interact with state in different siblings of components. For this, you may use redux.
If your application size is smaller, then you may also try using context api.
Hope, this helps to you.
Related
My parent component
import EditReview from './partials/editReview'
class VenueDetails extends Component {
constructor(props) {
super(props)
this.child = React.createRef();
}
render() {
return (
<div className="place-review-text">
<EditReview {...this.props}/>
</div>
)
}
}
My child component
class EditReview extends Component {
onEditClick(review, editIndex) {
console.log('ppp')
}
render() {
const { handleSubmit, user, pristine, index, commentCrossClick } = this.props
return (
<div>
<Field
name="content"
component={renderTextArea}
className="form-control"
label="Write your review..."
rows={2}
/>
</div>
)
}
}
export default EditReview
I need to call onEditClick from the parent component. I tried this but doesn't work.
Kindly help me
Edit
After upgrade I am getting this
Error in ./~/react-dom/lib/ReactServerRendering.js
Module not found: 'react/lib/React' in /home/user/ashish/LTC/lovethesecities-frontend/node_modules/react-dom/lib
After resolving all the errors call child function from parent in react 16
React docs have a example of this using refs
https://reactjs.org/docs/refs-and-the-dom.html
I’m also wondering the use case of wanting to do this, maybe some context could help with an answer?
Try doing it like this:
import EditReview from './partials/editReview'
class VenueDetails extends Component {
render() {
return (
<div className="place-review-text">
<EditReview ref={Ref => this.child=Ref } {...this.props} />
</div>
)
}
}
and call the function in parent component as this.child.onEditClick(param1,param2)
EDIT1:
if you have to do it with react 15.x itself what you can do it is create the function in parent and pass it as a prop to child
I just creating a project and use a several component for a page and pass data by using props to each components. The problem is, when I have already change data from parent component to child component by using props and I have update the data from parent component, the child component still using the old data.
The example is just like this:
class Child extends Component{
constructor(props){
super(props);
this.state = {
variabel : props.variable
}
}
render() {
return (
<div>
<h1>{this.state.variable}</h1>
</div>
)
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
variabel : 'Hello'
}
}
render() {
return (
<div>
<Child variable={this.state.variable} />
</div>
)
}
}
So, when I run the page and update the variabel state in Parent Component, Child Component still show the old value. How to make it updated as the Parent Component data? Or I must using Redux for this case?
In general you'll only want to keep one particular piece of state in one place. If you reassign it in the constructor of Child, it will not update when the parent's state updates. So something like this pattern should work:
class Child extends Component{
// Note that no constructor is needed as you are not initializing any state or binding any methods.
render() {
return (
<div>
<h1>{this.props.variable}</h1>
</div>
)
}
}
class Parent extends Component{
constructor(props){
super(props);
this.state = {
variable : 'Hello'
}
}
render() {
return (
<div>
<Child variable={this.state.variable} />
</div>
)
}
}
A warning note about not initializing state with props is in the React docs for constructor, as a matter of fact.
Mitch Lillie's answer is the correct one. You should have only one source of truth.
In general, it's a good idea to keep the state in the nearest common ancestor of the components that depend on the state. Then you pass the props down.
If, however, you need to keep a copy of the prop in the child state, you should use the life cycles that React provides.
Codepen Live Demo
class Child extends React.Component {
constructor(props) {
super(props);
this.state = {
variable: props.variable,
};
}
componentDidUpdate(prevProps, prevState, snapshot) {
if (this.props.variable !== prevState.variable) {
this.setState({
variable: this.props.variable,
});
}
}
render() {
const varState = this.state.variable;
const varProps = this.props.variable;
return (
<div>
Child props: {varProps}
<br />
Child state: {varState}
</div>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
setInterval(this.updateTime, 1000); // refresh every second
this.state = {
variable: new Date().toLocaleString(),
};
}
updateTime = () => {
this.setState({
variable: new Date().toLocaleString(),
});
}
render() {
const time = this.state.variable;
return (
<div>
<div>
Parent: {time}
</div>
<Child variable={time} />
</div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('container')
);
Currently trying to learn React by making a simple application that grabs data from the openFEC API.
I currently have two components defined in my application, a SearchBar and a Candidate component. This is what my App.js currently looks like:
class App extends Component {
constructor(props){
super(props);
this.state = { candidate: [], searchTerm: '' }
}
render() {
return (
<div className="App">
<SearchBar />
<Candidate candidate={this.state.candidate}/>
</div>
);
}
}
export default App;
Problem: I need to update the Candidate component based on the data I receive from the API response. However, I'm making the API call in the SearchBar component and have no way of updating the candidate state defined in the App component.
Should I make the API call in the App component instead? If not, is there a way to send the data I get back from the SearchBar component into my App component?
I think the best way to do this is have the API call in your App Component, and pass that function down as a prop to your SearchBar Component. Your parent component (in this case, App) should be holding on to all of the relevant information and passing down to it's children what they need.
It should look something like this:
class App extends Component {
...
handleSearch(term) {
//handle fetch here
.then(res => this.setState({candidate: res})
}
render() {
<div className="App">
<SearchBar handleSearch={this.handleSearch}/>
<Candidate candidate={this.state.candidate}/>
</div>
}
}
In this way, you can achieve this
class App extends Component {
constructor(props){
super(props);
this.state = { candidate: [], searchTerm: '' }
this.triggerSearch=this.triggerSearch.bind(this);
}
triggerSearch(searchTerm){
this.setState({searchTerm})
}
render() {
return (
<div className="App">
<SearchBar trigerSearch=
{(searchTerm)=>this.triggerSearch(searchTerm)} />
<Candidate candidate={this.state.candidate}/>
</div>
);
}
}
export default App;
You can achieve it this way (without making API call from App).
class App extends Component {
constructor(props){
super(props);
this.state = { candidate: [], searchTerm: '' }
this.onDataReceived = this.onDataReceived.bind(this);
}
onDataReceived(data){
this.setState({ candidate: data });
}
render() {
return (
<div className="App">
<SearchBar onDataReceived={this.onDataReceived}/>
<Candidate candidate={this.state.candidate}/>
</div>
);
}
}
Roughly what happens here is:
You can see how I passed a function as a props to the SearchBar component via onDataReceived props.
You can invoke that function from within SearchBar component (e.g. make API call and call function passed as props with API results).
Invoking onDataReceived function will trigger setState
Calling setState will call render and now the Candidate component will receive more recent data from state.
More.
I am woking on a sample ReactJS application, where I want to pass a variable from one component to another.
class Layout extends React.Component{
constructor(props) {
super(props);
this.state = {keyword: ''};
}
render() {
return (
<div className="wrapper">
<Search />
<Listing />
</div>
);
}
};
ReactDOM.render(
<Layout />, app
);
In the above code, I want to pass a variable from <Search /> component to <Listing /> component.
Rlijo you'd pass props to components as follows:
<Search paramA={someParam} paramB={anotherParam} />
and to use the props within the Search component you'd call this.props.paramA (if using classes).
The way you've got the components setup, you wouldn't be able to share the state from the Search component (i.e. the object in this.state within Search) with the Listing component. There are libraries such as Redux designed to solve problems of shared state across components.
Props (or variables or params) flow downward so you'd need to provide shared props from a parent component. See you could provide this.state.keyword as a prop to both Search and Listing as these two components sit inside this parent component.
You can make it with function like
class Layout extends React.Component {
constructor(props) {
super(props);
this.state = {
keyword: '',
yourVariable: null
};
}
sendVariable(newValue) {
this.setState({ yourVariable: newValue });
}
render() {
return (
<div className="wrapper">
<Search onChange={this.sendVariable.bind(this)} />
<Listing sendValue={this.state.yourVariable} />
</div>
);
}
};
class Search extends React.Component{
render(){
let variable = "";
return <div onClick={this.porps.onChange(variable)}></div>;
}
}
Or use React-redux.
I have a file named separatefile.jsx, in this file parent component name is Content and child component name is Child.
separatefile.jsx
import React from 'react';
import Parent from './learning.jsx';
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent/>
</div>
);
}
}
class Child extends React.Component {
render() {
return (
<div>
<h2>{this.props.childprop}</h2>
<h1>child class property</h1>
</div>
);
}
}
export default Content;
This is another file named as learning.jsx , this file has Parent component named as Parent and Child component named as a Children.
My questions is that i need to access Parent component property(parent component for learning.jsx) from Child component(child component for separatefile.jsx file)...
learning.jsx
import React from 'react';
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
</div>
);
}
}
export default Parent;
If I understood you correctly, you want to use Parent's state in your Children component?
You can pass it down the component tree as props, e.g.:
class Content extends React.Component {
constructor() {
super();
this.state = {
finding : 'i am finding'
}
}
render() {
return (
<div>
<Child childprop={this.state.finding}/>
<Parent finding={this.state.finding} />
</div>
);
}
}
class Parent extends React.Component {
constructor() {
super();
this.state = {
searching : 'i will find the solution'
}
}
render() {
return (
<div>
<Children finding={this.props.finding} childrenprop={this.state.searching}/>
</div>
);
}
}
class Children extends React.Component {
render() {
return (
<div>
<h2>{this.props.childrenprop}</h2>
<div>{this.props.finding}</div>
</div>
);
}
}
It's probably not a direct answer but if you are starting a new app I would recommend you to use Redux with react-redux.
Redux is a predictable state container for JavaScript apps.
It helps you write applications that behave consistently, run in different environments (client, server, and native), and are easy to test. On top of that, it provides a great developer experience, such as live code editing combined with a time traveling debugger.
It's very small library so it's easy to understand how everything works. It might be a good solution to your problem.
Todo app example
You can also check out awesome egghead.io free tutorial - Getting Started with Redux
Here is the answer about the redux benefits by its author Dan Abramov
The React documentation provides an answer.
For communication between two components that don't have a
parent-child relationship, you can set up your own global event
system. Subscribe to events in componentDidMount(), unsubscribe in
componentWillUnmount(), and call setState() when you receive an event.
Flux pattern is one of the possible ways to arrange this.