I'm using React-Redux to build a web app. In a parent component ("Layout"), I separate the page into two columns A and B.
Column A is a react component ("NavMenu") which also contains the title of the B column content. The B column is where the main component is displayed and it has its own title.
What I want to do is send this title from the B component to its sibling A component. What I've learned so far is that I need to send this data to the parent component (Layout) and then from there send it to A through a callback function. The function is a prop I've added to all children in this.props.children
in the Layout component.
In the Layout component, the content in B is one of the children component in this.props.children
.
Here is my code:
Layout.js
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { actionCreators } from '../store/Layout';
import { Col, Grid, Row } from 'react-bootstrap';
import NavMenu from './NavMenu'; // Component A
class Layout extends React.Component {
myCallback = titleFromChild => {
this.props.changeTitle(titleFromChild);
}
render() {
const childrenWithCallback = React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, { titleCallback: this.myCallback });
});
return (
this.props.isLoading ?
<p className='clearfix text-center'><span>Loading...</span></p>
:
<Grid fluid>
<Row>
<Col sm={3}>
<NavMenu title={this.props.title} />
</Col>
<Col sm={9}>
{childrenWithCallback}
{console.log(childrenWithCallback)}
// Console.log here shows that all children in this.props.children have the new prop
</Col>
</Row>
</Grid>
);
}}
export default connect(
state => state.layout,
dispatch => bindActionCreators(actionCreators, dispatch)
)(Layout);
I've added the function this.myCallback
to this.props.children
like in this tutorial.
LayoutStore.js
const changeTitleType = 'CHANGE_TITLE';
const initialState = {
title: "Child title",
isLoading: true
};
export const actionCreators = {
changeTitle: title => ({ type: changeTitleType, title })
}
export const reducer = (state, action) => {
state = state || initialState;
if (action.type === changeTitleType) {
return {
...state,
title: action.title
};
}
return state;
};
I've checked this similar question and this other similar question and I understand how it's supposed to work, but my problem goes a bit further: the child component doesn't receive the new injected prop.
ComponentB.js
import React from 'react';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
import { actionCreators } from '../store/ExpeditionCommands';
class ComponentB extends React.Component {
componentWillMount() {
this.props.titleCallback(this.props.title);
console.log(this)
//This is where I am not receiving the prop (titleCallback) I sent from the parent component
}
render() {
return (
<div>Hi there</div>
);
}
}
export default connect(
state => state.componentStoreB,
dispatch => bindActionCreators(actionCreators, dispatch)
)(ComponentB);
Why is my child component not receiving the new prop injected in this.props.children
? Do I need to pass through my redux store?