React Native - 基于子状态的父项条件样式

时间:2016-04-24 19:49:08

标签: reactjs react-native

我正在关注React Native教程并尝试调整它以显示歌曲列表而不是电影,并使用Switch组件添加切换功能。

我设法让这个工作,但现在我试图将开关的值发送回父级,以便可以应用条件样式。

当我尝试这样做时,我收到错误说

undefined is not an object (evaluating 'this.state.played')

这似乎是明智的,因为console中的togglePlayed语句似乎永远不会被调用。

import React, {
  AppRegistry,
  Component,
  Image,
  ListView,
  StyleSheet,
  Text,
  View,
  Switch
} from 'react-native';

var SONGS_DATA = {
  "songs" : [
    {
      "title" : "I Heard React Was Good",
      "artist" : "Martin",
      "played" : false
    },
    {
      "title" : "Stack Overflow",
      "artist" : "Martin",
      "played" : false
    }
  ]
}

var BasicSwitchExample = React.createClass({
  getInitialState() {
    return {
      played: false
    };
  },
  handlePlayed(value) {
    console.log('Switch has been toggled, new value is : ' + value)
    this.setState({played: value})
    this.props.callbackParent(value);
  },
  render() {
    return (
      <View> 
        <Switch
          onValueChange={this.handlePlayed}
          style={{marginBottom: 10}}
          value={this.state.played} />
      </View>
    );
  }
});

class AwesomeProject extends Component {
  constructor(props) {
    super(props);
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  }

  componentDidMount() {
    this.fetchData();
  }

  getInitialState() {
    return {
      played: false
    };
  }

  togglePlayed(value) {
    // this is never reached
    this.setState({played: value});
    console.log('Song has been played? ' + this.state.played);
  }

  fetchData() {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(SONGS_DATA.songs),
      loaded: true,
    });
  }

  render() {
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderSong}
        style={styles.listView}
      />
    );
  }

  renderLoadingView() {
    return (
      <View style={styles.container}>
        <Text>
          Loading songs...
        </Text>
      </View>
    );
  }

  renderSong(song) {
    return (
      // not sure if this syntax is correct
      <View style={this.state.played ? 'styles.container' : 'styles.played'}>
        <View style={styles.half}>
          <Text style={styles.title}>{song.title}</Text>
          <Text style={styles.artist}>{song.artist}</Text> 
        </View>
        <View style={styles.half}>
          <BasicSwitchExample callbackParent={() => this.togglePlayed} />
        </View>
      </View>
    );
  }
}

var styles = StyleSheet.create({
  /* styles here */
});

AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);

React Native Playground

任何指针都会很棒,因为我是React的新手,尤其是React Native。

1 个答案:

答案 0 :(得分:1)

您忘记将函数绑定到组件,它应该看起来像这样

class BasicSwitchExample extends Component{
    constructor(props){
      super(props);
      this.state = {
         played: false
       };
      this.handlePlayed = this.handlePlayed.bind(this);
    }
    handlePlayed(value){
        this.setState({played: value});
        this.props.callbackParent(value);
    }
    render() {
      return <View> 
        <Switch
          onValueChange={this.handlePlayed}
          style={{marginBottom: 10}}
          value={this.state.played} />
      </View>
  }
}
class AwesomeProject extends Component {
  constructor(props) {
    super(props);
    this.renderSong = this.renderSong.bind(this);
    this.togglePlayed = this.togglePlayed.bind(this); 
    this.fetchData = this.fetchData.bind(this);
    this.state = {
      dataSource: new ListView.DataSource({
        rowHasChanged: (row1, row2) => row1 !== row2,
      }),
      loaded: false,
    };
  }

  componentDidMount() {
    this.fetchData();
  }

  togglePlayed(value) {
    // this is never reached
    this.setState({played: value});
    console.log('Song has been played? ' + this.state.played);
  }

  fetchData() {
    this.setState({
      dataSource: this.state.dataSource.cloneWithRows(SONGS_DATA.songs),
      loaded: true,
    });
  }

  render() {
    if (!this.state.loaded) {
      return this.renderLoadingView();
    }

    return (
      <ListView
        dataSource={this.state.dataSource}
        renderRow={this.renderSong}
        style={styles.listView}
      />
    );
  }

  renderLoadingView() {
    return (
      <View style={styles.container}>
        <Text>
          Loading songs...
        </Text>
      </View>
    );
  }

  renderSong(song) {
    return (
      // not sure if this syntax is correct
      <View style={this.state.played ? 'styles.container' : 'styles.played'}>
        <View style={styles.half}>
          <Text style={styles.title}>{song.title}</Text>
          <Text style={styles.artist}>{song.artist}</Text> 
        </View>
        <View style={styles.half}>
          <BasicSwitchExample callbackParent={this.togglePlayed} />
        </View>
      </View>
    );
  }
}