Karlo Delalic
Karlo Delalic

Reputation: 101

How can I update the Youtube video using my search function?

I am trying to pass a search query from an input in searchBar.js to app.js and then back into its child Video in order to search for a video and play it.

I am not sure what I'm doing wrong, as the video is not updating.

Do I need to rerender the video component or something like that?

I am using the react-youtube module for react integration with the YoutubeAPI.

https://github.com/kdelalic/Shuffle

app.js (parent) class:

import React, { Component } from 'react';
import "../css/app.css";
import Video from "./video";
import TopBar from "./topBar";

export default class App extends Component {

    constructor(props) {
        super(props);
        this.state = {
            searchQuery: null
        };    
    }

    myCallback(dataFromChild) {
        this.setState({ searchQuery: dataFromChild });
    }

    render() {
        return (
          <div>
            <TopBar parentCallBack={this.myCallback}/>
            <Video query={this.state.searchQuery} />
          </div>
        );
    }
}

topBar.js class:

import React, { Component } from 'react';
import {Navbar} from 'react-materialize';
import '../css/topBar.css';
import SearchBar from './searchBar'


export default class TopBar extends Component {

  myCallback(dataFromChild) {
    this.props.parentCallBack(dataFromChild);
  }

  render() {
    return (
      <div className="wrapper">
        <Navbar className="logo" brand='Shuffle+' right>
          <SearchBar callBack={this.myCallback}/>
        </Navbar>
      </div>
    );
  }
}

searchBar.js class:

import React, { Component } from 'react';
import {NavItem, Icon} from 'react-materialize';
import '../css/searchBar.css';

export default class SearchBar extends Component {

  constructor(props) {
    super(props);
    this.state = {value: ''};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }


  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    this.props.callBack(this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <div className="wrapper">
        <form className="form" onSubmit={this.handleSubmit}>
          <label>
            <input className="input" type="text" value={this.state.value} onChange={this.handleChange} />
          </label>
        </form>
        <NavItem className="searchButton">
              <Icon>search</Icon>
        </NavItem>
      </div>
    );
  }
}

Upvotes: 0

Views: 57

Answers (1)

Josh Alexy
Josh Alexy

Reputation: 411

This looks relatively ok with one exception.

myCallback(dataFromChild) {
  this.props.parentCallBack(dataFromChild);
}

// ...when being used
<SearchBar callBack={this.myCallback}/>

The problem is, when the callBack function is called from the Child, the this of the function is set to the child component.

You have a couple options here when passing a function into a child as a callback.

Bind in property

<SearchBar callBack={this.myCallback.bind(this)}/>

The downside is that the function is copied every time the render function is called.

Bind in constructor

As you've already done, you can bind the this context of the function to the parent in the constructor.

class TopBar extends Component {
  constructor() {
    // ...
    this.myCallback = this.myCallback.bind(this);
  }
}

Downside is that it's terse and you have to write this for every function you need to bind to the component.

ES Class Property Arrow Functions

This is my personal favorite. The downside is that you need babel and the stage 2 proposal to transpile your code.

class TopBar extends Component {
  myCallback = () => {
    // ...
  }

  render() {
    <SearchBar callback={this.myCallback} />
  }
}

Upvotes: 1

Related Questions