如何防止组件在数据提取之前呈现子项

时间:2018-05-17 00:48:11

标签: javascript reactjs redux react-redux redux-form

我有一个Dashboard组件,用于呈现从后端服务器获取数据的卡阵列。用户可以通过提交表单来创建其他卡片,然后将表单重定向回仪表板页面。

我的问题是,在提交表单时,javascript错误无法读取属性"包含"未定义的'抛出,仪表板不呈现。如果我手动刷新页面,列表将按预期使用新卡呈现。我使用Array.includes方法根据filterText状态值过滤卡片。是否发生此错误是因为调用render时尚未获取数据?如果是这样,我怎样才能强制组件等到渲染前有数据?请参阅下面的组件和redux操作。

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 :(得分:2)

与@JasonWarta提到的类似,值得注意的是,当falsenullundefined被返回时,React不呈现任何内容,因此您通常可以使用&&比使用条件(&#34;三元&#34;)运算符更简洁:

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,并且该组件也不会呈现任何内容(与您返回{{时相同) 1}})。

答案 1 :(得分:0)

我在这种情况下使用过三元运算符。您可能需要调整模式的检查部分,具体取决于您的redux模式返回的内容。如果null为假,则会返回this.props.cards值。

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
        }
    );
}

答案 2 :(得分:0)

作为其他答案的替代方案,如果渲染函数中没有带if语句的数据,则可以返回其他合适的答案。我更喜欢像渲染之外的过滤器一样移动函数。也许另一种(更好的?)方法是在mapStateToProps函数中进行过滤。

另外,如果我没错,你不需要将任何东西传递给你的handleChange函数。因为您从CardList组件返回filterText然后设置状态。

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>
        );       
 }