2017-01-26 10 views
0

ListViewはデータソースが設定される前にレンダリングを試みます(ComponentDidMount) これは常に空です。私がloadData()を呼び出そうとすると、それはそれを表示します。React Native:データソースが設定される前にListViewがレンダリングされます

ロードを完了する前にコンポーネントのレンダリングを避けるにはどうすればよいですか?

アクション:

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

リデューサー:

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

コンポーネント自体:

export default class Courses extends Component { 
 
\t static propTypes = { 
 
\t \t user: PropTypes.string.isRequired, 
 
    users: PropTypes.array.isRequired, 
 
\t \t courseDetails: PropTypes.func.isRequired, 
 
\t \t courses: PropTypes.object.isRequired, 
 
    getCourses: PropTypes.func.isRequired, 
 
    openProfile: PropTypes.func.isRequired 
 
\t }; 
 

 
\t constructor(props) { 
 
     super(props); 
 
     this.state = { 
 
      dataSource: new ListView.DataSource({ 
 
      rowHasChanged: (row1, row2) => row1 !== row2, 
 
      }), 
 
      dataLoaded: 0 
 
     }; 
 
    } 
 

 
\t componentWillMount(){ 
 

 
\t } 
 

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

 

 
\t render() { 
 
    return (
 
     <View style={{ height: Platform.OS == "ios" ? height - 114 : height - 130 }}> 
 
     <ListView 
 
      dataSource={this.state.dataSource} 
 
      renderRow={this.renderRow.bind(this)} 
 
     /> 
 
     </View> 
 
    ); 
 
\t } 
 
}

UPDATE @stinodes: enter image description here

これは、問題を修正しますが、私はそれを行うための適切な方法をそのないと思う:

componentWillMount(){ 
 
    setTimeout(()=>{ 
 
     console.log('!run!'); 
 
     this.loadData(); 
 
    }, 1000); 
 
\t } 
 

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

答えて

1

componentDidMountの代わりにcomponentWillMount -hookを使用できます。
最初のものを使用して、レンダリングの前に設定します。後者は、コンポーネントが初めてレンダリングされた後に起動します。


編集:あなたはあなたのグローバルな状態を更新した後、あなたのデータはあなたの小道具に渡されるReduxのを使用しているので、あなたがたときに、コンポーネントマウントあなたのコースを取得することになるでしょう。 componentDidMountフックにデータを読み込むことで、これを実行できます。
しかし、reduxはコンポーネントの小道にコースを渡すため、asyncというキーワードは必要ありません。

コンポーネントの小道具が更新されると、再レンダリングも実行されます。 dataSourceをご自分の状態にしたい場合は、componentWillReceivePropsフックを使用できます。このフックは、コンポーネントが新しいプロパティを受け取ったときに起動されます。
これを呼び出すと、入力したデータソースを自分の状態に追加できます。このには新しいレンダリングが行われません。

例:

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

    } 

    /* ... */ 
} 
+0

残念ながらそれは助けにはなりませんでした。 – Ataomega

+0

@Ataomegaあなたのロードデータが非同期であることを見落としました。 'getCourses'から実際にデータを取得していますか?また、 'async'を使用しているので、後でその関数をプロップから取得するのではなく、その関数が返すようにすることもできます。 – stinodes

+0

はい、データを返します。しかし、私は小道具からデータを取得する必要があります。それは還元です。リストビュー用のdataSourceを設定してください – Ataomega

関連する問題