【问题标题】:React Native: ListView renders before dataSource being setReact Native:ListView 在设置数据源之前呈现
【发布时间】:2017-06-11 15:45:56
【问题描述】:

Listview 在设置数据源之前尝试渲染 (ComponentDidMount) 所以它总是空的。如果我尝试调用 loadData() 它将显示它。

如何避免在加载完成之前渲染组件?

行动:

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

更新 @stinodes:

这解决了问题,但我认为这不是正确的方法:

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

【问题讨论】:

    标签: javascript reactjs react-native


    【解决方案1】:

    您可以使用componentWillMount-hook 代替componentDidMount
    使用第一个,在渲染之前设置它。后者在组件第一次渲染后触发。


    edit:由于您使用 redux 来更新全局状态,然后将数据传递到 props,因此您需要在组件挂载时获取课程。通过将数据加载到componentDidMount-hook 中,您就可以做到这一点。
    但是,您不需要 async 关键字,因为无论如何 redux 都会通过组件的 props 传递课程。

    当你的组件的 props 更新时,它也会重新渲染。如果你想让你的dataSource 处于你的状态,你可以使用componentWillReceiveProps-hook。当您的组件接收到新属性时,将触发此钩子。
    调用此方法时,您可以将填充的数据源添加到您的状态。这不会导致新的渲染。

    例子:

    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
            })
    
        }
    
        /* ... */
    }
    

    【讨论】:

    • 不幸的是它没有帮助。
    • @Ataomega 我忽略了您的加载数据是异步的这一事实。您确定您实际上是从您的getCourses 获取数据吗?此外,您还不如让该函数返回课程,而不是事后从道具中获取,因为无论如何您都在使用async
    • 是的,它返回数据。但我需要从道具中获取数据。这是还原。并为列表视图设置数据源
    • @Ataomega 我根据您使用 Redux 的事实编辑了我的答案。让我知道它是否有帮助,或者您是否仍然遇到问题。您可能希望从问题中删除一些臃肿的代码,并添加一些数据加载代码(例如您的操作和减速器)。
    • 我已经更新了问题。不幸的是,你所说的也没有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-22
    • 1970-01-01
    • 2018-05-23
    相关资源
    最近更新 更多