Реагировать на обновление компонента после загрузки данных - PullRequest
0 голосов
/ 26 декабря 2018

Итак, у меня есть компонент, который показывает категории из firestore, компонент не показывает ничего в первый раз, но когда я снова нажимаю кнопку navbar, он показывает данные, хранящиеся в 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)

А вот файл редуктора:

 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?

Ответы [ 2 ]

0 голосов
/ 26 декабря 2018

Есть несколько вещей, которые нужно понять.Во-первых, this.props.getCategories() выполняет действие асинхронного характера и, следовательно, в следующей строке this.setState({categoriesList: this.props.categories}); мы не получим требуемые данные.

Во-вторых, сохранение реквизитов для состояния без каких-либо изменений не требуется.и приводит к осложнениям.Поэтому старайтесь использовать реквизит напрямую, не сохраняя его.В случае, если вы изменяете полученный реквизит, убедитесь, что вы переопределяете getDerivedStateFromProps.

В-третьих, попробуйте использовать componentDidMount для выполнения таких асинхронных операций, чем componentWillMount.См. , когда использовать componentWillMount вместо componentDidMount .

В-четвертых ( важно в вашем случае ), Reducer не должно содержать асинхронных операций.Редуктор должен быть синхронной операцией, которая вернет новое состояние.В вашем случае вам нужно получить данные в другом месте, а затем dispatch в вашем db.collection(..).then обратном вызове .Вы также можете использовать redux-thunk , если вы используете слишком много асинхронных операций для обновления своего Redx.

Поэтому ответ @ Mis94 должен работать, если вы следуете четвертому пункту возврата новогосостояние в редукторе, а не мутирование в редуксе непосредственно в db().then callback

0 голосов
/ 26 декабря 2018

Во-первых, вам не нужно хранить реквизиты компонента в объекте состояния.Это на самом деле считается анти-паттерном в реакции.Вместо этого просто используйте ваш реквизит непосредственно в методе рендеринга:

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) здесь .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...