简体   繁体   中英

React Native: ListView renders before dataSource being set

Listview tries to render, before the datasource is set (ComponentDidMount) So it's always empty. if i try to call loadData() it will show it then.

How can i avoid component rendering before loading finishes?

Actions :

 export const GET_COURSES = 'GET_COURSES'; export const GET_COURSES_FAILED = 'GET_COURSES_FAILED'; import getCoursesAPI from '../common/Functions'; export const getCourses = (users) => { return dispatch => { getCoursesAPI(users) .then((data)=>{ const {courseList, lectureList} = data; return dispatch(coursesSuccess(courseList, lectureList)); }) .catch(()=>{ return dispatch(coursesFailed()); }); }; } const coursesSuccess = (courses, lectures) => { return { type: GET_COURSES, payload: { courses, lectures } } }; const coursesFailed = () => { return { type: GET_COURSES_FAILED } }; 

Reducer :

 import * as types from "./courses.actions"; export const INITIAL_STATE = { courses: {} }; export default function courses(state = INITIAL_STATE, action){ const {courses, lectures} = state; switch(action.type){ case types.GET_COURSES: return { ...state, courses: action.payload.courses, lectures: action.payload.lectures }; case types.GET_COURSES_FAILED: return { ...state, courses: courses , lectures: lectures }; default: return state; } } 

Component itself :

 export default class Courses extends Component { static propTypes = { user: PropTypes.string.isRequired, users: PropTypes.array.isRequired, courseDetails: PropTypes.func.isRequired, courses: PropTypes.object.isRequired, getCourses: PropTypes.func.isRequired, openProfile: PropTypes.func.isRequired }; constructor(props) { super(props); this.state = { dataSource: new ListView.DataSource({ rowHasChanged: (row1, row2) => row1 !== row2, }), dataLoaded: 0 }; } componentWillMount(){ } componentDidMount(){ this.props.getCourses(this.props.users); } componentWillReceiveProps(newProps) { const courses = newProps.courses.courses[this.props.user] this.setState({ dataSource: this.state.dataSource.cloneWithRows(courses), dataLoaded: courses.length }); } render() { return ( <View style={{ height: Platform.OS == "ios" ? height - 114 : height - 130 }}> <ListView dataSource={this.state.dataSource} renderRow={this.renderRow.bind(this)} /> </View> ); } } 

UPDATE @stinodes : 在此处输入图片说明

This fixes the issue but i think its not the proper way to do it :

 componentWillMount(){ setTimeout(()=>{ console.log('!run!'); this.loadData(); }, 1000); } componentDidMount(){ } async loadData(){ const {user, users, getCourses, courses} = this.props; await getCourses(users); const data = courses[user]; this.setState({ dataSource: this.state.dataSource.cloneWithRows(data), dataLoaded: data.length }); } 

You can use the componentWillMount -hook instead of the componentDidMount .
Using the first, sets it before the render. The latter fires after the component is rendered for the first time.


edit : Since you're using redux to update your global state and then get your data passed into your props, you will want to fetch your courses when your component mounts. You have this in place, by loading your data in the componentDidMount -hook.
However, you won't need the async keyword, since redux will be passing the courses through your component's props anyway.

When your component's props are updated, it will do a rerender as well. If you want to have your dataSource in your state, you can use the componentWillReceiveProps -hook. This hook will be fired when your component receives new properties.
When this is called, you can add your populated datasource to your state. This won't cause a new render.

Example:

class Courses extends Component {
    /* ... */

    componentDidMount() {

        // Will fetch your data asynchronously
        this.props.getCourses(this.props.users);

    }

    // This hook gets the new props passed. Old props are
    // still available in this.props
    componentWillReceiveProps(newProps) {

        const courses = newProps.courses.courses[this.props.user]
        this.setState({
            dataSource: this.state.dataSource.cloneWithRows(courses),
            dataLoaded: courses.length
        })

    }

    /* ... */
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM