繁体   English   中英

通过子组件更改父状态时,React重新渲染

[英]React Re-renders When Parent State is Changed Through Child Component

在App.js中,我将setURL(page){ ... }作为对HealthForm的支持。 在HealthForm中,我有一个输入字段,该字段接受URL的String和一个按钮,该按钮发起对后端服务器的提取调用,并且一些数据会在promise对象中接收回来。 我也叫that.props.changeUrl(that.state.someURL); 在promiseStatus函数内部,因为那是我唯一可以放置它而不收到以下警告的地方:

Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

但是,每次调用that.props.changeUrl(that.state.someURL) ,页面都会重新渲染。 基本上-输入字段和由于fetch调用而呈现的其他功能-全部重置。 但是App.js中的url状态会更新。

为什么在调用父项道具时整个页面都重新渲染?

如果仅删除了那行that.props.changeUrl(that.state.someURL)但该应用程序不会重新呈现,但是它当然不会更改该应用程序的状态

我需要页面不重新呈现,因为重要信息是在fetch调用之后呈现的,由于重新呈现会重置该路由,因此无法看到。

App.js

class App extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            url: '',

        };
        this.setURL = this.setURL.bind(this);
    }

    setURL(link) {
        this.setState({
            url: link
        });
    }

    render(){
        return(

            <MuiThemeProvider>
                <Router>
                    <div className="App">
                        <Route path="/" component={Header}></Route>

                        <Route path="/health" component={()=>(
                            <HealthForm changeUrl={this.setURL}/>)}></Route>

                        <Route path="/path1" component={wForm}></Route>
                        <Route path="/path2" component={xForm}></Route>
                        <Route path="/path3" component={yForm}></Route>
                        <Route path="/path4" component={zForm}></Route>

                    </div>
                </Router>
            </MuiThemeProvider>
        );
    }   
}

HealthForm.js

class HealthForm extends React.Component {
  constructor(props) {
   super(props);
    this.state = {
        exampleURL: '',
        exampleURLError: '',
        status: '',
        showStatus: false
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
 }

 validate = () => {
 //…checks for input errors
       }

 handleChange(event) {
    this.setState({
        [event.target.name]: event.target.value
    });
 }

 handleSubmit(event) {
    event.preventDefault();
    const err = this.validate();
    let that = this;
    if (!err) {
                   this.setState({
        exampleURLError: ''
        });
        console.log(this.state);
        var data = this.state.exampleURL

        fetch('htpp://...', {
                    method: 'POST',
                    body: JSON.stringify(data)
                })
                .then((result) => {
                    var promiseStatus = result.text();
                    promiseStatus.then(function (value) {
                        that.setState({
                            status: value,
                            showStatus: true
                        });
                        that.props.changeUrl(that.state.jarvisURL);
                    });
                }).catch((error) => {
                    console.log(error);
                });
    }
 }

 render() {
        return (
            <form>  
            <TextField
              ...
            />
            <br/>

             <Button variant="contained" size="small" color="primary"     onClick={e => this.handleSubmit(e)} >
                Check
            </Button>
            <br />  <br /> 

             ...

            </form>  
        );
 }
}
export default HealthForm;

之所以发生这种情况,是因为您在App组件上调用setState() ,导致其重新呈现,包括重新创建您设置的所有路由。 我不确定您使用的是哪个路由器,但是似乎它是在路由下重新创建组件,可能是通过再次调用作为道具传入的component函数并获取HealthForm组件的新实例。

我假设App中的所有组件都要求您将状态存储在App中,这就是为什么要将其放置在其中? 如果不是,请将其向下移到HealthForm组件中,但是如果是这样,可能是时候考虑将状态外部存储到组件中了,例如,在诸如Redux之类的状态容器中或其他具有Flux风格的东西中。

编辑:我认为您的问题的根源在这里:

<Route path="/health" component={()=>(<HealthForm changeUrl={this.setURL}/>)}></Route>

事实上,函数是作为component prop传递的,每次都会导致component的新实例。 我可以看到为什么需要这样做,以将对setURL()的引用传递到HealthForm -通过从组件中提取状态也可以避免这种情况。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM