【问题标题】:React update component after loading data加载数据后反应更新组件
【发布时间】:2019-05-24 20:55:42
【问题描述】:

所以我有一个显示来自 firestore 的类别的组件,该组件第一次不显示任何内容,但是当我再次单击导航栏按钮时,它确实显示了存储在 firestore 中的数据。

这是组件文件:

import * as React from "react";
import Category from "./Category";
import connect from "react-redux/es/connect/connect";
import {getCategories} from "../reducers/actions/categoryAction";

class CategoriesList extends React.Component{
    constructor(props) {
        super(props);
        this.state = ({
            categoriesList: [{}]
        })
    }

    componentWillMount() {
        this.props.getCategories();
        this.setState({categoriesList: this.props.categories});
        this.forceUpdate();
    }

    render() {
        return (
            <div className={'container categories'}>
                <div className={'row center'} onClick={() => this.props.history.push('/addcategories')}>
                    <div className={'col s24 m12'}>
                        <p>Create New Category</p>
                    </div>
                </div>

                <div className={'row'}>
                    <div className={'col s24 m12'}>
                        {/*{() => this.renderCategories()}*/}


                        {this.state.categoriesList && this.state.categoriesList.map(category => {
                            return <Category category={category} key={category.id}/>
                        })}
                    </div>
                </div>
            </div>
        );
    }
}

const mapDisptachToProps = (dispatch) => {
    return {
        getCategories: () => dispatch(getCategories()),
    }
};

const mapStateToProps = (state) => {
    return {
        categories: state.category.categories
    }
};

export default connect(mapStateToProps, mapDisptachToProps)(CategoriesList)

这里是reducer文件:

 import db from '../firebaseConfig'


const initState = {
    categories: []
};

const categoryReducer = (state=initState, action) => {
    switch (action.type) {
        case 'CREATE_CATEGORY':
            db.collection("Categories").add({
                category: action.category.name
            })
                .then(function(docRef) {
                    db.collection("Categories").get().then((querySnapshot) => {
                        querySnapshot.forEach((doc) => {
                            // console.log(`${doc.id} => ${doc.data().category}`);
                            if(doc.id === docRef.id) {
                                state.categories.push({id: doc.id, name: doc.data().category});
                                console.log(state.categories)
                            }
                        });
                    });
                })
                .catch(function(error) {
                    console.error("Error adding document: ", error);
                });
            break;

        case 'GET_CATEGORIES':
            console.log('Getting data from firestore');

            db.collection("Categories").get().then((querySnapshot) => {
                if(state.categories.length !== querySnapshot.size) {
                    querySnapshot.forEach((doc) => {
                        state.categories.push({id: doc.id, name: doc.data().category});
                    });
                }
            });
            break;
    }
  return state;
};

export default categoryReducer

有没有办法在完全加载数据后更新组件?还是一种加载 initalState 中所有数据的方法?

【问题讨论】:

  • 您是否尝试使用 ComponentDidMount 而不是 componentWillMount ?
  • @LeonardoLobato 是的,我试过componentDidUpdate(prevProps) { if (prevProps.categoriesList.length !== this.categoriesList.length) { this.forceUpdate(); } }
  • getCategories() 是一个 AJAX 请求。当您在该请求之后 setState 时,尚未从 AJAX 响应中设置 categories
  • @Hoyen 我应该使用延迟吗?
  • componentDidMount 不是 componentDidUpdate... 可能你的意思是 componetWillReceiveProps 没有 componentDidUpdate。如果您使用正确的生命周期方法,您可能不需要它,您可以使用 this.forceUpdate()。尝试 componentDidMount,如果仍然不起作用,请尝试 componentWillReceiveProps

标签: node.js reactjs firebase redux google-cloud-firestore


【解决方案1】:

首先,您不需要将组件的 props 存储在 state 对象中。这实际上被认为是 anti-pattern 的反应。而不是这样做,只需直接在渲染方法中使用你的道具:

render() {
    return (
        <div className={'container categories'}>
            <div className={'row center'} onClick={() => this.props.history.push('/addcategories')}>
                <div className={'col s24 m12'}>
                    <p>Create New Category</p>
                </div>
            </div>

            <div className={'row'}>
                <div className={'col s24 m12'}>
                    {/*{() => this.renderCategories()}*/}


                    {this.props.categories && this.props.categories.map(category => {
                        return <Category category={category} key={category.id}/>
                    })}
                </div>
            </div>
        </div>
    );
}

因此在您的componentWillMount 中您只需要发起您的请求:

componentWillMount() {
    this.props.getCategories();
}

你也可以在componentDidMount()生命周期方法中做到这一点。

现在,当您的请求得到解决并且您的类别在商店 (Redux) 中更新时,它们将再次传递给您的组件,从而使其更新。每次更新存储在商店中的类别时也会发生这种情况。

您也不必像这样调用forceUpdate,除非您有实现shouldComponentUpdate 生命周期方法的组件并且您希望它们忽略它并执行强制更新。您可以阅读所有这些生命周期方法(如果您使用 React,则必须阅读)here

【讨论】:

  • 你确定你的请求真的返回数据吗...你试过 console.log(querySnapshot);在 .then() 里面?
【解决方案2】:

人们需要了解的东西很少。首先,this.props.getCategories() 执行了一个异步操作,因此在下一行 this.setState({categoriesList: this.props.categories}); 中,我们不会获得所需的数据。

其次,将 props 存储到 state 而不进行任何修改是不必要的,并且会导致复杂化。所以尽量不存储直接使用道具。如果您正在修改获得的道具,请确保您适当地覆盖getDerivedStateFromProps

第三,尝试使用componentDidMount来执行这种异步操作,而不是componentWillMount。参考when to use componentWillMount instead of componentDidMount

第四(在你的情况下很重要),Reducer 不应包含异步操作。 Reducer 应该是一个同步操作,它会返回一个新的状态。在您的情况下,您需要在其他地方获取数据,然后在 db.collection(..).then 回调 中获取 dispatch。如果你使用太多异步操作来更新你的 redux,你也可以使用redux-thunk

所以@Mis94 答案应该可以工作,如果你遵循在reducer 中返回新状态的第四点,而不是直接在db().then callback 中改变redux

【讨论】:

  • 在此处阅读有关 Redux reducer 的信息:redux.js.org/basics/reducers redux.js.org/recipes/structuring-reducers/structuring-reducers 如第一个链接中所述:请记住,reducer 必须是纯的。给定相同的参数,它应该计算下一个状态并返回它。没有惊喜。没有副作用。没有 API 调用。没有突变。只是一个计算。因此,根据 Redux 文档,您不应该进行 API 调用或检索其中的数据。
猜你喜欢
  • 1970-01-01
  • 2021-10-26
  • 1970-01-01
  • 2017-09-15
  • 2022-06-29
  • 2019-09-19
  • 2023-03-19
  • 2019-08-30
  • 2020-10-26
相关资源
最近更新 更多