Как предотвратить рендеринг дочернего компонента до получения данных - PullRequest
0 голосов
/ 17 мая 2018

У меня есть компонент Dashboard, который отображает массив карточек с данными, полученными с внутреннего сервера. Пользователи могут создавать дополнительные карты, отправив форму, которая затем перенаправляет их обратно на страницу панели инструментов.

Моя проблема заключается в том, что при отправке формы выдается ошибка javascript «Невозможно прочитать свойство», включающая «undefined», и панель инструментов не отображается. Если я обновлю страницу вручную, список будет отображаться, как и ожидалось, с новой картой. Я использую метод Array.include для фильтрации карточек на основе значения состояния filterText. Эта ошибка возникает из-за того, что данные не были получены при вызове рендера? Если это так, как я могу заставить компонент ждать, пока не будет данных перед рендерингом? Пожалуйста, ознакомьтесь с компонентами и редукционным действием ниже.

const CardList = (props) =>  {

    const cards = props.cards.map(({ _id, title}) => {
            return (
                <Card key={_id} title={title} />
            )
        });

        return (
            <div className="container">
                <input onChange={ (e) => props.handleChange(e.target.value) } />
                <div className="row">
                    {cards}
                </div>
            </div>
        );
} 
export default CardList;

export class Dashboard extends Component {
    constructor(props) {
        super(props);
        this.state = {
            filterText: ''
        }
    }
    componentDidMount() {
        this.props.fetchCards();
    } 

    handleChange = (filterText) => {
        this.setState({filterText});
    }

    render() {
        const cardList = this.props.cards.filter(card => 
            card.title.includes(this.state.filterText.trim().toLowerCase())
        );
        return (
            <div>
                <CardList cards={cardList}
                    handleChange={filterText => this.handleChange(filterText)} />
            </div>
        );
    }
};
function mapStateToProps({ cards: { cards }}) {
    return {
        cards,
    }
}
export default connect(mapStateToProps, {fetchCards})(Dashboard);

export class SurveyForm extends Component {
render() {
        return (
            <div>
               <form>
                 <Field component={CardField} type="text" 
                     label={'title'} name={'title'} key={'title'} />
                 <Button type="submit" onClick={() => submitCard(formValues, history)}>Next</Button>
               </form>
            </div>
        );
    }
}
REDUX ACTION DISPATCHER:
export const submitCard = (values, history) => async dispatch => {
    const res = await axios.post('/api/cards', values);

    try {
        dispatch({ type: SUBMIT_CARD_SUCCESS, payload: res.data });
        dispatch({ type: FETCH_USER, payload: res.data })
    }
    catch(err) {
        dispatch({ type: SUBMIT_CARD_ERROR, error: err });
    }

    history.push('/cards');
}

Ответы [ 3 ]

0 голосов
/ 17 мая 2018

Подобно тому, что упоминал @JasonWarta, стоит отметить, что React ничего не отображает при возврате false, null или undefined, поэтому обычно вы можете использовать &&, чтобы быть более кратким, чем использованиеусловный («троичный») оператор:

render() {
  return this.props.cards && (
    <div>
      <CardList 
        cards={this.props.cards.filter(card => card.title.includes(this.state.filterText.trim().toLowerCase())}
        handleChange={filterText => this.handleChange(filterText)}
      />
    </div>
  );
}

Поскольку && замыкает накоротко, последняя часть не будет оценена, поэтому вы можете избежать TypeError s, и компонент также не будет отображать содержимое(так же, как при возврате null).

0 голосов
/ 17 мая 2018

В качестве альтернативы другим ответам вы можете вернуть что-то еще подходящее, если в вашей функции рендеринга нет данных с оператором if. Я предпочитаю перемещать такие функции, как ваш фильтр, за пределы рендера. Может быть, еще один (лучше?) Подход заключается в использовании этого фильтра в вашей функции mapStateToProps.

Кроме того, если я не ошибаюсь, вам не нужно ничего передавать в функцию handleChange. Поскольку вы возвращаете filterText из компонента CardList, вы устанавливаете свое состояние.

cardList = () => this.props.cards.filter(card => 
            card.title.includes(this.state.filterText.trim().toLowerCase()));

render() {
 if ( !this.props.cards.length ) {
        return <p>No cards</p>
        // or return <SpinnerComponent />
    }
 return (
            <div>
                <CardList cards={this.cardList()}
                    handleChange={this.handleChange} />
            </div>
        );       
 }
0 голосов
/ 17 мая 2018

Я использовал троичные операторы в такой ситуации. Возможно, вам придется скорректировать контрольную часть шаблона в зависимости от того, что возвращает ваш шаблон с избыточностью. Значение null возвращается, если this.props.cards - Falsey.

render() {
    return (
        {this.props.cards
            ?
                <div>
                    <CardList 
                        cards={this.props.cards.filter(card => card.title.includes(this.state.filterText.trim().toLowerCase())}
                        handleChange={filterText => this.handleChange(filterText)}
                    >
                    </CardList>
                </div>
            :
                null
        }
    );
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...