Reputation: 45
I'm a beginner in React and stuck with some problem. I have two components. one is parent which passes its state to child component. the other is child which receives passed state and use it as props. What I wanted to do is when I click the list element in parent component(Detailsrch), its state changes and affect to child component(Btnfunctionlocal) so it will re render. This is for selecting address from parent component, and detailed address from child component.
I tried to use this.forceupdate and getderivedstatefromprops but It seems just make the work more difficult. And I tried to put parent's state into child's state. I used console.log to see what is happening, but console.log prints correct value but value in the browser doesn't change from the first one that selected from parent component.
import React, { Component } from 'react';
import { Jumbotron } from 'react-bootstrap';
import { Btnfunctionlocal } from './Locals/Btnfunction';
import './Detailsrch.css';
class Detailsrch extends Component {
constructor(props) {
super(props);
this.state = {
local: '',
localdetail: ''
}
this.whichlocal = (e) => {
console.dir(e.target);
// Here is the code that changes parent component's state
this.setState({
local: e.target.innerText
})
// From here to
let selector = document.getElementsByClassName('locals');
let i = 0;
while (selector[i]) {
selector[i].classList.remove('localclick');
i++;
}
if (e.target.className === 'localtext') {
e.target.parentElement.classList.add('localclick');
} else {
e.target.classList.add('localclick');
}
// here is for change css after click
}
}
render() {
console.log(this.state);
return (
<Jumbotron className='searchjumbo'>
<p>Address</p>
<ul>
{['All', 'Seoul', 'Incheon', 'Busan'].map((value, index) => {
return <li className='locals' onClick={this.whichlocal} name={'localdiv' + index} key={index}><span className='localtext' name={'localdiv' + index}>{value}</span></li>
})}
</ul>
{this.state.local?<Btnfunctionlocal local={this.state.local} />:''}
<hr className='firsthr' />
</Jumbotron>
);
}
};
export default Detailsrch;
export class Btnfunctionlocal extends Component {
constructor(props){
super(props)
const local = {
Seoul: ['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구'],
Incheon: ['강화군', '계양구', '미추홀구', '남동구', '동구', '부평구', '서구', '연수구', '옹진구', '중구'],
Busan: ['강서구', '금정구', '기장군', '남구', '동구', '동래구', '부산진구', '북구', '사상구', '사하구', '서구', '수영구', '연제구', '영도구', '중구', '해운대구']
}
this.locallist = local[this.props.local].slice();
}
render(){
return(
<div className='localdiv'>
{this.locallist.map((value, index)=>{
return <div className={"searchselector"} key={index}>{value}</div>
})}
</div>
)
}
}
export class Btnfunctionlocal extends Component {
constructor(props) {
super(props)
const local = {
Seoul: ['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구'],
Incheon: ['강화군', '계양구', '미추홀구', '남동구', '동구', '부평구', '서구', '연수구', '옹진구', '중구'],
Busan: ['강서구', '금정구', '기장군', '남구', '동구', '동래구', '부산진구', '북구', '사상구', '사하구', '서구', '수영구', '연제구', '영도구', '중구', '해운대구']
}
this.state = {
local: []
}
}
componentDidMount() {
this.setState({
local: local[this.props.local].slice()
})
}
render() {
return (
<div className='localdiv'>
{this.state.local.slice().map((value, index) => {
return <div className={"searchselector"} key={index}>{value}</div>
})}
</div>
)
}
}
I expect when I click parent's list element, the child's elements will change, but except the first click, nothing changes.
Upvotes: 0
Views: 752
Reputation: 8774
So there are several things, which I would change. But first to answer your question: You copy the prop into your local state on mount in your child component, but you don't update the state, if the parent props change. There is a way to fix that using componentDidUpdate:
componentDidUpdate(prevProps) {
if(prevProps.local !== this.props.local) {
this.setState({
local: local[this.props.local].slice()
})
}
}
This will listen to prop changes and update your local state, which you access during your render method accordingly. Alternatively, you could directly use the parent prop during your render method and remove both componentDidUpdate and componentDidMount, like this:
render() {
return (
<div className='localdiv'>
{local[this.props.local].slice().map((value, index) => {
return <div className={"searchselector"} key={index}>{value}</div>
})}
</div>
)
}
Additionally, I would not use document.getElementsByClassName
at all and handle it with a ternary operation and js in css styles.
Lastly, I would access the value of your change with e.target.value, because innerText might be different than value.
Upvotes: 1