Reputation: 1734
My React app has three components. Two of them are child components and the other is parent. I need to pass a data (projectId) from one child component to the other child through the parent component and after receiving the data, fire a function. As my example, I'm sending projectId from ChildOne to Parent and then send projectId from Parent to ChildTwo. ChildTwo has a function called setProject(projectId) and I need to fire it once the projectID is received. The problem is I can't get the function getProjectId fired in ChildTwo by clicking on the button in ChildOne. I also tried with componentDidMount and componentWillReceiveProps which are not working for me. How can I do this?
Here what I tried
ChildOne :
class ChildOne extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: 3,
};
}
sendProjectId = (projectId) => {
this.props.sendId(projectId)
}
render() {
return(
<button onClick={() => this.sendProjectId(this.state.projectId)}>
Click
</button>
)
}
}
Parent:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: '',
};
}
getId = (proId) => {
this.setState({
projectId : proId
})
}
render() {
return(
<div>
<CildOne sendId={this.getId} />
<CildTwo sendOneId={this.state.projectId} />
</div>
)
}
}
ChildTwo:
class ChildTwo extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: '',
};
}
getProjectId = (this.props.sendOneId) => {
//Do something with this.props.sendOneId
}
render() {
return(
<div></div>
)
}
}
Upvotes: 3
Views: 923
Reputation: 557
Our you can try a functional component or hooks if you want to set some state
function ChildOne(props) {
const [projectId, setProjectId] = useState(3);
function sendProjectId(data){
props.sendId(projectId)
}
return(
<button onClick={() => sendProjectId(projectId)}>
Click
</button>
)
}
function ChildTwo(props) {
const [state, setState] = useState('')
function getProjectId(data) {
//Do something with this.props.sendOneId
console.log(`data here ${data}`)
return false;
}
getProjectId(props.sendOneId)
return (
<div>
</div>
)
}
function Parent(){
const [projectId, setProjectId] = useState('');
function getId(proId) {
setProjectId(proId)
}
return(
<div>
<ChildOne sendId={getId} />
<ChildTwo sendOneId={projectId} />
</div>
)
}
Upvotes: 1
Reputation: 63587
You should probably use componentDidUpdate
with a condition to check to see whether the projectId in state
needs to be updated when sendOneId
changes. You can then use setState
s callback to call getProjectId
:
componentDidUpdate() {
const { projectId: currentProjectId } = this.state;
const { sendOneId: projectId } = this.props;
if (projectId !== currentProjectId) {
this.setState({ projectId }, () => this.getProjectId());
}
}
Full working example:
class ChildOne extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: 3,
};
}
sendProjectId = (projectId) => {
this.props.sendId(projectId)
}
render() {
return (
<button onClick={() => this.sendProjectId(this.state.projectId)}>
Click
</button>
);
}
}
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: '',
};
}
getId = (projectId) => {
this.setState({ projectId });
}
render() {
return (
<div>
<ChildOne sendId={this.getId} />
<ChildTwo sendOneId={this.state.projectId} />
</div>
)
}
}
class ChildTwo extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: '',
};
}
componentDidUpdate() {
const { projectId: currentProjectId } = this.state;
const { sendOneId: projectId } = this.props;
if (projectId !== currentProjectId) {
this.setState({ projectId }, () => this.getProjectId());
}
}
getProjectId = () => {
console.log(this.state.projectId);
}
render() {
return (
<div></div>
);
}
}
ReactDOM.render(
<Parent />,
document.getElementById('container')
);
<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>
<div id="container"></div>
Upvotes: 1
Reputation: 6378
You did a mistake in getProjectId
function of ChildTwo
component.
Your function cannot receive anything as a parameter from prop.
So, your function should look like:
getProjectId = (sendOneId) => {
//Do something with this.props.sendOneId
}
Then you should use componentWillReceiveProps
like this:
componentWillReceiveProps(nextProps) {
if (this.props.sendOneId !== nextProps.sendOneId) {
this.getProjectId(nextProps.sendOneId);
}
}
Here is a working codesandbox example that I created to fix your problem: https://codesandbox.io/s/5v4rn7qnll
Upvotes: 1
Reputation: 19224
This would depend on what ChildTwo
wants to accomplish with the said data.
Case 1:
ChildTwo
intends to fetch some data with the corresponding projectId
and display it in the component. Then, you can easily fetch this data in the parent component and pass the data down as props
.
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: '',
dataForChildTwo: null,
};
}
getId = (proId) => {
this.setState({
projectId : proId,
dataForChildTwo: fetchData(proId)
})
}
render() {
return(
<div>
<CildOne sendId={this.getId} />
<CildTwo data={this.state.dataForChildTwo} />
</div>
)
}
}
Case 2:
ChildTwo
intends to make some change to something inside it when projectId
changes. Then you can use componentDidUpdate
hook to see if prop changed and respond to it.
class ChildTwo extends React.Component {
constructor(props) {
super(props);
this.state = {
projectId: '',
};
}
getProjectId = (this.props.sendOneId) => {
//Do something with this.props.sendOneId
}
componentDidUpdate(prevProps) {
if(this.props.projectId!==prevProps.projectId) {
// do something
}
}
render() {
return(
<div></div>
)
}
}
Case 3:
If none of the above cases work for you, then you can manually reload the complete component when the projectId
changes using a key
attribute:
<CildTwo key={this.state.projectId} sendOneId={this.state.projectId} />
Note: This reloads the whole component quite unnecessarily.
Upvotes: 3