简体   繁体   English

如何更新componentDidMount内部的状态?

[英]How to update state inside componentDidMount?

I'm using fetch API and I want update the const called state inside the componentDidMount() (with onChange) which are being using in a template string. 我正在使用fetch API,并且我想在componentDidMount()(使用onChange)中更新正在模板字符串中使用的const状态。 How do I update this value with onChange? 如何使用onChange更新此值?

import React, {Component} from 'react'

class Data extends Component {
    constructor() {
        super();
        this.state = {
            items: {},
            value: '',
            isLoaded: false
        }
    }

    handleChange(e) {
        this.setState({value: e.target.value});
    }


    componentDidMount() {

        const state = this.state.value

        fetch(`http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${state}`)
        .then(res => res.json())
        .then(json => {
            this.setState({
                isLoaded: true,
                items: json,
            })
        });
    }


    render(){
        const {isLoaded} = this.state;

        if(!isLoaded) {
            return <div>Loading...</div>
        }

        return(
            <div>
                <select onChange={this.handleChange}>
                    <option value="America/Chicago">Chicago</option>
                    <option value="America/Sao_Paulo">São Paulo</option>
                </select>
            </div>
        )
    }
}


So, how can I update the value of the const state with onChange? 那么,如何使用onChange更新const状态的值?

componentDidMount() is called when the React component has mounted, and it happens only once. 安装React组件时会调用componentDidMount() ,并且它只会发生一次。

If I understand correctly, you want to call fetch on each change of the value stored under value state property, so the componentDidMount method is not a perfect place to put that kind of logic. 如果我理解正确,您想对存储在value状态属性下的value每次更改调用fetch ,因此componentDidMount方法不是放置这种逻辑的理想场所。 You can create a separate method called fetchData and pass the value to it as an argument. 您可以创建一个名为fetchData的单独方法,并将该值作为参数传递给它。 Then you can call that method on componentDidMount as well as on each value property change (in our case - onChange event). 然后,您可以在componentDidMount以及每个值属性更改(在我们的情况下为onChange事件)中调用该方法。

 import React, { Component } from "react"; class Data extends Component { constructor(props) { super(props); this.state = { items: {}, value: "America/Chicago", isLoaded: false }; this.handleChange = this.handleChange.bind(this); } componentDidMount() { const { value } = this.state; this.fetchData(value); } handleChange(event) { const value = event.target.value; this.setState({ value }); this.fetchData(value); } render() { const { isLoaded, value, items } = this.state; if (!isLoaded) { return <div>Loading...</div>; } return ( <div> <select onChange={this.handleChange} value={value}> <option value="America/Chicago">Chicago</option> <option value="America/Sao_Paulo">São Paulo</option> </select> {JSON.stringify(items)} </div> ); } fetchData(value) { fetch( `https://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${value}` ) .then(res => res.json()) .then(json => { this.setState({ isLoaded: true, items: json }); }); } } 

Working demo: https://codesandbox.io/embed/728jnjprmq 工作演示: https : //codesandbox.io/embed/728jnjprmq

Tomasz's code has 2 mistakes: (1) it fetches resources w/o checking if the component has been unmounted; Tomasz的代码有2个错误:(1)不获取组件是否已卸载而获取资源。 (2) it starts the request w/o updating the UI first. (2)它首先启动不更新UI的请求。

I would do the following instead: 我将改为执行以下操作:

import React, {Component} from 'react'

class Data extends Component {
    constructor() {
        super();
        this.state = {
            items: {},
            value: '',
            isLoaded: false
        }

        this._isMounted = false;

        // don't forget to bind your methods
        this.handleChange = this.handleChange.bind(this);
    }

    componentDidMount() {
        this._isMounted = true;
    }

    componentWillUnmount() {
        this._isMounted = false;
    }

    handleChange(e) {
        const value = e.target.value;
        this.setState({ value }, () => {
            if (!this._isMounted) return;
            const url = `http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${value}`
            fetch(url).then((res) => {
                if (!this._isMounted) return;
                const data = res.json();
                this.setState({ isLoaded: true, items: data });
            })
        });
    }

    render(){
        const { isLoaded } = this.state;

        if(!isLoaded) {
            return <div>Loading...</div>
        }

        return(
            <div>
                <select onChange={this.handleChange}>
                    <option value="America/Chicago">Chicago</option>
                    <option value="America/Sao_Paulo">São Paulo</option>
                </select>
            </div>
        )
    }
}

Assuming you want to refresh the value of this.state.items when the user changes the value of the select , you can do this in the onChange . 假设您要在用户更改select的值时刷新this.state.items的值,则可以在onChange执行此操作。 However, your code is in a few (incorrect) pieces. 但是,您的代码有几段(不正确)。 Let's start from the top. 让我们从头开始。

First of all, you're setting the value property of state to '' , so your componentDidMount function is going to see that value. 首先,将statevalue属性设置为'' ,因此componentDidMount函数将看到该值。 I assume that's no good, so let's strip that out of componentDidMount entirely. 我认为那不好,所以让我们将其完全从componentDidMount中删除。 We can move this code to the handleChange function instead, but it'll still need to be changed: 我们可以将这段代码移到handleChange函数中,但是仍然需要更改它:

handleChange(e) {
    this.setState({value: e.target.value});

    fetch(`http://api.timezonedb.com/v2.1/get-time-zone?key=J9X3EOT2EM8U&format=json&by=zone&zone=${e.target.value}`)
    .then(res => res.json())
    .then(json => {
        this.setState({
            isLoaded: true,
            items: json,
        })
    });
}

Notice my change - we can't access the value from the state, because setState is asynchronous, and so the value hasn't been updated by this point. 注意我的更改-我们无法从状态访问值,因为setState是异步的,因此此时尚未更新值。 We know the value comes from the select though. 我们知道价值来自select

The other thing you could do to improve this functionality is to turn the select into a controlled component. 改善此功能的另一件事是将select变成受控组件。 To do this, you just have to set the value of the field to be controlled by the state of this component. 为此,您只需要设置要由该组件的状态控制的字段的值即可。 Since you're using an onChange listener for this, it makes the field a controlled component (if you weren't using an onChange, it would be a read-only field. 由于您为此使用了onChange侦听器,因此它使该字段成为受控组件(如果您不使用onChange,则它将是一个只读字段。

The loading variable in state appears to be being used incorrectly, I'm guessing you just need to check if there's data in 'items'. state中的loading变量似乎未正确使用,我猜您只需要检查'items'中是否有数据。 I'll remove this for now, but you could come back to this. 我现在将其删除,但是您可以回到此位置。

render(){
    const {isLoaded} = this.state;

    if(!isLoaded) {
        return <div>Loading...</div>
    }

    return(
        <div>
            <select onChange={this.handleChange}>
                <option value="America/Chicago">Chicago</option>
                <option value="America/Sao_Paulo">São Paulo</option>
            </select>
        </div>
    )
}

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

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