Search code examples
javascriptjsonreact-nativereact-native-router-flux

Getting specific JSON data after clicking a button


I'm building a React Native app that works with JSON data and shows the upcoming movies. It looks like this: https://image.ibb.co/kuOt9m/app.png . My problem is whenever I click the Summary button I get all the summaries, for all the movies. What i want is to get a specific summary for the movie I clicked. In the JSON there's a movie id that is totally unique and I guess I should set it on the Button or the CardSection itself. My code looks like this:

import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import axios from 'axios';
import MovieSummary from './MovieSummary';

class SummaryList extends Component {

  state = { movies: [] };

  componentDidMount() {
    axios.get('https://api.themoviedb.org/3/movie/upcoming?api_key=22d8da68cffba151bfa886d5003aac02&language=en-US&page=1')
      .then(response => this.setState({ movies: response.data.results }));
  }

  renderSummary() {
    return this.state.movies.map(movie =>
      <MovieSummary key={movie.id} movie={movie} />
    );
  }

  render() {
    console.log(this.state);

    return (
      <ScrollView>
        {this.renderSummary()}
      </ScrollView>
    );
  }
}

export default SummaryList;

then in another class i show the data like this:

import React from 'react';
import { View, Text } from 'react-native';

const MovieSummary = (props) => (
  <View>
    <Text>
      {props.movie.overview}
    </Text>
  </View>
);

export default MovieSummary;

and then with a Router class (react-native-router-flux library) I use Router/Scene to connect the two screens. I'm gonna post the CardSection.js or Button.js code if it's gonna make it anymore clear and there's where I need to add an ID.

edit: adding more information

my CardSection.js looks like this:

import React from 'react';
import { View } from 'react-native';

const CardSection = (props) => (
    <View style={styles.containerStyle}>
      {props.children}
    </View>
  );

const styles = {
  containerStyle: {
    *some view styles*
  }
};

export default CardSection;

my Button.js looks like this:

import React from 'react';
import { Text, TouchableOpacity } from 'react-native';

const Button = ({ onPress, children }) => (
    <TouchableOpacity
      onPress={onPress}
      style={styles.buttonStyle}
    >
      <Text style={styles.textStyle}>
        {children}
      </Text>
    </TouchableOpacity>
  );

const styles = {
  buttonStyle: {
    *button styles*
  },

  textStyle: {
    *text styles*
  }

};

export default Button;

Solution

  • First thing, I think there's a bit of confusion about your second screen, you're calling it SummaryList and it's working on an array of movies - whereas if I understand correctly you want your second screen to just deal with one movie.

    I'd rename a few things:

    • MoviesList is fine
    • MovieDetail -> MoviesListItem (these are rows in your MovieList, renaming to avoid confusion with your second screen)
    • SummaryDetail is fine (this will be your single-movie scene. I'd probably actually call this MovieDetail but that would get confusing!)

    Forget about SummaryList - we don't need it. You only have one list we're concerned about, that's MoviesList.

    First, modify your Router so that you have a MoviesList and a SummaryDetail scene:

    // Router.js
    // ...
    const RouterComponent = () => (
      <Router
        navigationBarStyle={styles.viewStyle}
        titleStyle={styles.textStyle}
        sceneStyle={{ paddingTop: 53 }}
      >
        <Scene key="upcoming" component={MoviesList} title="Upcoming Movies" />
        <Scene
          key="summaryDetail"
          component={SummaryDetail}
          title="Summary Detail"
          leftButtonIconStyle={{ tintColor: '#a52a2a' }}
        />
      </Router>
    );
    // ...
    

    So now your MoviesListItem is the component with a summary Button in it. This needs to lead to your SummaryDetail scene. You can navigate to your SummaryDetail scene by calling Actions.summaryDetail() from react-native-router-flux, but you actually want to tell this scene which movie it's dealing with. Pass the movie (which you already have as a prop of MovieListItem) as a param, via an argument to Actions.summaryDetail(...) like this:

    // MovieListItem.js
    // ...
        <View style={{ justifyContent: 'flex-end' }}>
          <Button
            onPress={() => {
            Actions.summaryDetail({ movie: props.movie });  // <- Important bit!
          }}>
            Summary
          </Button>
        </View>
    // ...
    

    Now, you should have the movie available in your SummaryDetail screen as the movie prop.

    // SummaryDetail.js
    // ...
    const SummaryDetail = (props) => (
      <View>
        <Text>
          {props.movie.overview}
        </Text>
      </View>
    );
    // ...
    

    You might want to split off parts of SummaryDetail into separate presentational components later, and you might want to turn it into a class and use componentDidMount to fetch some extra movie detail you don't already have. But this should be enough to get you started with one movie on a second screen.