Responding to your question, if , it is not only possible to send information on both the props
and the state
of a component parent to its / s son / s but that is the approach React proposes.
The data handling in React is hierarchical and unidirectional (top-down), that is:
The state must be known and modified by the top element in common to the child elements. For more info see React docs: Lifting state up
The information passes from a parent element to a child element , state
is used for data volatile and mutable , while props
is data < strong> immutable . The correct flow is for a parent to send his state
as prop
of his / her children / s, so that by changing the state
in the parent, the render()
is invoked and affects the props
of children. That is, the children modify their behavior and rendering according to the state of the father (stored in their props
) and their own internal state.
Example : moving from the parent element to the sheet elements the props
color and size
Image taken from: link
Mini example:
I have implemented a mini example to visualize this, which basically consists of a main page and a navigation menu ( very ugly by the way ):
<Menu />
component:
- Keep in its props a list of items to show, received from the father
- Maintains a Boolean
showItems
in its props
-
Render conditionally the
items
based on the previous property
<Page />
component:
- Maintains in its state whether the page actions are enabled or not
- Create component
<Menu />
indicating its prop showItems
for conditional rendering
- It has a handler function to enable / disable actions, which invokes
this.setState()
and therefore if there are changes it triggers the render()
(React standard behavior)
class Menu extends React.Component{
/* renders the items conditionally */
render(){
return (
<div>
<h3> {this.props.title} </h3>
{this.props.showItems && (<ul> {this.props.items} </ul>)}
</div>) ;
}
}
class Page extends React.Component{
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
// set initial state with enableActions = true to make the checkbox checked by default
this.state ={enableActions: true};
}
render(){
{/* creates <button> for each action item */}
let actions = this.props.actions.map((item)=>{return <li><button> {item} </button></li> });
return(
<div>
<span>Enable menu actions </span>
{/* checkbox that changes the state */}
<input type="checkbox" checked={this.state.enableActions} onChange ={this.handleChange}/>
{/* (Parent State -> Child prop) - create <Menu /> passing state "enableActions" as "showItems" property */}
<Menu title="Navigation bar" items = {actions} showItems= {this.state.enableActions} />
</div>
);
}
handleChange(e){
{/* updates state with the current checked value of the checkbox */}
this.setState({enableActions : e.target.checked});
}
}
let items = ["Help","Login","About us"];
ReactDOM.render(<Page actions = {items} />, document.getElementById('root'));
body{
font-family: Tahoma;
}
button{
background: #bcd4e6;
border: 1px solid #4c8dbd;
color: #4c8dbd;
width: 70px;
}
h3{
background: #0095ff;
color: white;
margin: 0;
}
ul{
margin: 0;
padding: 0;
list-style-type: none;
}
<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 = "root">
<div>