【问题标题】:child Component doesn't re render after parent passes changed state父组件通过更改状态后子组件不会重新渲染
【发布时间】:2019-12-12 05:40:42
【问题描述】:

我是 React 的初学者,遇到了一些问题。 我有两个组件。一个是将其状态传递给子组件的父组件。另一个是接收传递状态并将其用作道具的孩子。 我想要做的是当我单击父组件(Detailsrch)中的列表元素时,它的状态会发生变化并影响到子组件(Btnfunctionlocal),因此它将重新呈现。 这是从父组件中选择地址,从子组件中选择详细地址。

我尝试使用 this.forceupdate 和 getderivedstatefromprops 但似乎只会让工作变得更加困难。我试图把父母的状态变成孩子的状态。我使用 console.log 查看发生了什么,但 console.log 打印出正确的值,但浏览器中的值与从父组件中选择的第一个值没有变化。




这里是父组件

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>
        )
    }
}



我希望当我单击父级的列表元素时,子级的元素会发生变化,但除了第一次单击外,没有任何变化。

【问题讨论】:

  • 只要状态发生变化,React 组件就会重新渲染。当您在父组件中更新您的状态时,它将重新呈现,但在子组件中您将其存储在 this.locallist 或 state local 中,这不是正确的方法。直接在渲染内部使用 local[this.props.local].slice() 或 prop 值,而不是存储它。如果您仍想以状态存储,请存储但之后使用 componentWillReceiveProps 如果反应版本低于 16.8 来比较 nextProps 和以前的 props 值。如果它们不同,您可以再次更新状态。
  • componentWillReceiveProps 已弃用,而应使用 componentDidUpdate。
  • @YogeshDevgun 非常感谢。这是一个问题。如果 props 发生变化,组件不会自动重新渲染吗?还是应该使用 componentDidUpdate 告诉组件更改?
  • @momo1108:没有组件不会在道具更改时重新渲染。它将始终在状态更改时重新渲染。
  • @Domino987 是的,它已被弃用,具体取决于安装的 react 版本 componentDidUpdate 或 componentWillReceiveProps 可用于检测道具的任何变化。

标签: reactjs


【解决方案1】:

所以有几件事我会改变。但首先要回答你的问题: 在子组件中挂载时将道具复制到本地状态,但如果父道具发生更改,则不会更新状态。有一种方法可以使用 componentDidUpdate 解决这个问题:

componentDidUpdate(prevProps) {
    if(prevProps.local !== this.props.local) {
        this.setState({
             local: local[this.props.local].slice()
        })
    }        
}

这将监听 prop 更改并更新您的本地状态,您可以在渲染方法期间相应地访问这些状态。或者,您可以在渲染方法期间直接使用 parent 属性并删除 componentDidUpdate 和 componentDidMount,如下所示:

render() {
    return (
        <div className='localdiv'>
            {local[this.props.local].slice().map((value, index) => {
                return <div className={"searchselector"} key={index}>{value}</div>
            })}
        </div>
    )
}

此外,我根本不会使用document.getElementsByClassName,而是使用三元运算和css 样式的js 来处理它。 最后,我将使用 e.target.value 访问您更改的值,因为 innerText 可能与值不同。

【讨论】:

    猜你喜欢
    • 2019-09-21
    • 2019-01-08
    • 2019-06-29
    • 2020-12-30
    • 2021-06-20
    • 1970-01-01
    • 2016-02-23
    • 1970-01-01
    • 2019-06-17
    相关资源
    最近更新 更多