访问在另一个函数中分配的值

时间:2019-04-23 09:24:07

标签: javascript reactjs

我想从另一个函数中的值访问值。这两个函数在同一作用域内,而不是嵌套的。

我尝试仅使用一个函数ComponentDidMount()并增加了外部查询的范围,以便可以在内部访问该值。它可以工作,但在控制台中始终显示错误,但显示正确。我认为这是因为我对多个事物使用相同的引用。但是,如果我缩小范围,但仍将其保留为一个功能,它将无法正常工作。我认为这与创建两个函数并且无法访问另一个函数中的值相同。但是我不明白,尽管我在第一个函数内部设置了值的状态。为什么它会在我在构造函数中初始化的第二个参数中恢复默认值?

这就是我现在所拥有的。请注意,ComponentWillMount可以是任何其他函数。

componentWillMount = () => {
    let query = [];
    this.unsub = this.props.firebase.users().doc(this.props.firebase.userId()).get().then(doc => {
        query.push(doc.data().LinkedUsername)
        const lU = this.props.firebase.users().where("email", "==", query[0])
        lU.get().then(snapshot => {
            // console.log(snapshot.docs[0].id)
            this.setState({queryId: snapshot.docs[0].id});

            console.log(this.state.queryId)

        })
    })
}

componentDidMount = () => {
    this.setState({loading: true});

    console.log(this.state.queryId)

    this.unsubscribe = this.props.firebase
        .users().doc(this.props.firebase.userId()).collection('tasks')
        .onSnapshot(snapshot => {
            let items = [];
            snapshot.forEach(doc =>
                (doc.data().status === false) ?
                    items.push({...doc.data(), uid: doc.id})
                    :
                    null
            );
            this.setState({
                items,
                loading: false,
            });
        });
}

记下控制台位置。第一个控制台返回所需的值,但第二个则不。它返回未定义的值或在构造函数中初始化时分配的值,如下所示

constructor(props) {
    super(props);
    this.state = {
        loading: false,
        items: [],
        // queryId: null
    };
    this.classes = props;
}

如果我在下面进行操作,它会在屏幕上提供所需的输出,但会在控制台中多次抛出相同的错误。

componentDidMount = () => {
    this.setState({loading: true});
    console.log(this.state.queryId)
    let query = [];
    this.unsub = this.props.firebase.users().doc(this.props.firebase.userId()).get().then(doc => {
        query.push(doc.data().LinkedUsername)
        const lU = this.props.firebase.users().where("email", "==", query[0])
        lU.get().then(snapshot => {
            // console.log(snapshot.docs[0].id)
            this.setState({queryId: snapshot.docs[0].id});
            console.log(this.state.queryId)
            this.unsubscribe = this.props.firebase
                .users().doc(this.props.firebase.userId()).collection('tasks')
                .onSnapshot(snapshot => {
                    let items = [];
                    snapshot.forEach(doc =>
                        (doc.data().status === false) ?
                            items.push({...doc.data(), uid: doc.id})
                            :
                            null
                    );
                    this.setState({
                        items,
                        loading: false,
                    });
                });
        })
    })
}

但是,如果我在下面进行操作,则不会。检查倒数第二行和倒数第三行括号的位置差异。

constructor(props) {
    super(props);
    this.state = {
        loading: false,
        items: [],
        // queryId: null
    };
    this.classes = props;
}

如果我在下面进行操作,它会在屏幕上提供所需的输出,但会在控制台中多次抛出相同的错误。

componentDidMount = () => {
    this.setState({loading: true});
    console.log(this.state.queryId)
    let query = [];
    this.unsub = this.props.firebase.users().doc(this.props.firebase.userId()).get().then(doc => {
        query.push(doc.data().LinkedUsername)
        const lU = this.props.firebase.users().where("email", "==", query[0])
        lU.get().then(snapshot => {
            // console.log(snapshot.docs[0].id)
            this.setState({queryId: snapshot.docs[0].id});
            console.log(this.state.queryId)
        })
    })
    this.unsubscribe = this.props.firebase
        .users().doc(this.props.firebase.userId()).collection('tasks')
        .onSnapshot(snapshot => {
            let items = [];
            snapshot.forEach(doc =>
                (doc.data().status === false) ?
                    items.push({...doc.data(), uid: doc.id})
                    :
                    null
            );
            this.setState({
                items,
                loading: false,
            });
        });
}

实际结果

undefined index.js:43
Qz1mFFBgPrUFPfO1YFqVxfVpAbE2 index.js:36 

预期结果

Qz1mFFBgPrUFPfO1YFqVxfVpAbE2 index.js:43
Qz1mFFBgPrUFPfO1YFqVxfVpAbE2 index.js:36

2 个答案:

答案 0 :(得分:0)

componentDidMount()在初始渲染后被调用。 setState()是异步调用。

因此,基本上,当您调用componentWillMount() setState()并且状态值被更新时,componentDidMount()已经被调用。

避免在构造函数或componentWillMount()中调用或使用api

您的网络请求应位于componentDidMount()

答案 1 :(得分:0)

正如@Ravi所说,您不应在componentWillMount内调用网络请求。您可以在componentDidMount内部安全地调用网络请求。

在您的第一个代码段中,您正在this.setState()中调用componentWillMount(),并在firebase响应后设置状态。从Firebase获取数据并获得响应后需要设置状态。

componentDidMount()将在组件安装后立即被调用。从Firebase获取数据并将其设置为componentWillMount()的状态会花费一些时间,第二个console.log()将为您提供undefined或初始化时分配的任何内容在构造函数中。

在第二个代码段中,您的构造函数如下:

constructor(props) {
        super(props);
        this.state = {
            loading: false,
            items: [],
            // queryId: null
        };
        this.classes = props;
}

正如您在构造函数中注释了queryId并将其记录在componentDidMount()中一样,由于未初始化,它将抛出错误或在控制台中给您undefined在构造函数中。

由于React / ReactNative是一个声明性框架,即您仅告诉React / ReactNative需要什么,而无需担心如何做,因此可以按照以下方法进行网络请求,并且当状态更改时,所有状态值将为在整个组件内部进行了更新:

constructor(props) {
        super(props);
        this.state = {
            loading: true,
            items: [],
            queryId: null
        };
 }


componentDidMount = () => {
       //your network request
       fetch('fetch_url')
       .then((response) => response.json())
       .then((response) => {
            this.setState({ //making result to be globally accessible
                loading: false,
                items: response.items,
                queryId: response.queryId
            });
       })
       .catch((error) => {
               //handle error
       })
}

但是,如果要一个接一个地执行多个请求,则可以使用async/await,也可以制作一系列then语句,如下所示:

fetch('fetch_url')
       .then((response) => response.json())
       .then((response) => {
            this.setState({ //making result to be globally accessible
                loading: false,
                items: response.items,
                queryId: response.queryId
            }); 
            return response.queryId;
       })
       .then((response) => { //'queryId' returned from the upper 'then'
            //other operations       
       })
       .catch((error) => {
               //handle error
       })