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

标签 javascript reactjs react-props

在 App.js 中,我将 setURL(page){ ... } 作为 prop 传递给 HealthForm。 在 HealthForm 中,我有一个输入字段,它接受 URL 字符串和一个按钮,该按钮启动对我的后端服务器的获取调用,并在 Promise 对象中接收一些数据。我还在 PromiseStatus 函数内调用 that.props.changeUrl(that.state.someURL); 因为这是我可以放置它而不会收到以下警告的唯一位置:

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 状态会更新。

为什么当我调用父 props 时整个页面会重新渲染?

如果只是删除了 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(),导致它重新渲染,包括重新创建您已经创建的所有路由设置。我不确定您到底使用的是哪个路由器,但它似乎正在重新创建路由下的组件,可能是通过调用再次作为 prop 传入的 component 函数并获取一个新实例您的 HealthForm 组件。

我假设应用程序中的所有组件都需要您在 App 中存储的状态,这就是您将其放在那里的原因?如果没有,请将其向下移动到 HealthForm 组件中,但如果是这样,也许是时候考虑将状态存储在组件外部了,例如在像 Redux 这样的状态容器中或 Flux 中的其他内容风格。

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

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

事实上,函数作为 component 属性传递,每次都会产生一个新的组件实例。我明白为什么你需要这样做,以获取对 setURL() 的引用传递到 HealthForm 中 - 这也可以通过从组件。

关于javascript - 当通过子组件更改父状态时,React 重新渲染,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51622012/

相关文章:

javascript - 可以使用 React 中的属性将哪些不同类型的 Prop 从一个组件发送到另一个组件?

javascript - 如何使用 Webpack 2 热重载 Sass?

reactjs - react 路由器浏览器历史记录removeListen?

javascript - 如何从父组件调用子组件中的函数

reactjs - React 组件 props 中的展开运算符

javascript - mongoosejs 返回带有更改对象的 model.find

javascript - Jquery .css 行高不工作

c# - 更新面板 AsyncPostBack 和 PostBack 触发器

javascript - Filereader 输出保存到变量

javascript - React Hooks - 更改父样式以反射(reflect)子 onClick