Today I started learning React, and I want to fetch movies from the TMDb API. I have this code:
getMovies() {
const APIKey = "MYAPI";
fetch(`https://api.themoviedb.org/3/search/company?api_key=${APIKey}&query=${argument}&page=1`)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
}
And in my render() I have this:
return (
<Fragment>
<div className="Main">
<button onClick={this.getMovies.bind('spider-man')}>Get</button>
</div>
</Fragment>
)
I want to pass 'spider-man' as an argument to do the search in the TMDb API. Hope you can help me!
This is how you can pass the parameter to the class component function, using {() => {...}} or other option could be this.getMovies.bind(this, 'spider-man')
getMovies(movie) { // your code here}
Option 1:
return (
<Fragment>
<div className="Main">
<button onClick={() => this.getMovies('spider-man')}>Get</button>
</div>
</Fragment>
)
Option 2:
return (
<Fragment>
<div className="Main">
<button onClick={() => this.getMovies.bind(this,'spider-man')}>Get</button>
</div>
</Fragment>
)
This is mainly divided into two categories
Class components
Functional Components
Class components
Consider you have your code as follow:
getMovies(movieName){...}
render(){
<button onClick={/*Attach event here*/}>Get</button>
}
There can be 4 ways
Using binding in the constructor, This is a recommended way of binding a method.
class Movie{
constructor(props){
super(props);
this.getMovies = this.getMovies.bind(this);
}
getMovies(movieName){ //your code }
render(){
<button onClick={this.getMovies('some_movie_name')}>Get</button>
}
}
Using binding in the render method itself. In terms of performance, it's the same as the previous one. The first one is a little cleaner for me.
class Movie{
getMovies(movieName){ //your code }
render(){
<button onClick={this.getMovies.bind('some_movie_name')}>Get</button>
}
}
Using arrow function syntax in render().
class Movie{
getMovies(movieName){ //your code }
render(){
<button onClick={()=>this.getMovies('some_movie_name')}>Get</button>
}
}
Using the arrow function in classes. This will have an impact on overall performance. You can read more about this here.
class Movie{
getMovies = (movieName) => { //your code }
render(){
<button onClick={this.getMovies('some_movie_name')}>Get</button>
}
}
Function components
Consider you have your code as follow:
function getMovies(movieName){ //your code }
return(){
<button onClick={/*Attach event here*/}>Get</button>
}
There aren't many variations for the function component. Using either an arrow or regular function expression to define a function.
function Movie(){
function getMovies(movieName){...} //or const getMovies = (movieName) => {...}
return(
<button onClick={()=>getMovies('some_movie_name')}>Get</button>
{/*
if not arguments
<button onClick={getMovies}>Get</button>
*/}
)
}
Related
I'm currently learning React and i am working through 'The Road to React' by Robin Wieruch.
I've just refactored some code from a stateful to a functional stateless component like so:
function Search(props) {
const { value, onChange, children } = props;
return (
<form>
{children} <input
type="text"
value={value}
onChange={onChange}
/>
</form>
);
}
Gets Refactored to:
const Search = ({ value, onChange, children }) => {
<form>
{children} <input
type="text"
value={value}
onChange={onChange}
/>
</form>
}
However nothing is rendering anymore. Are functional stateless components called the same was as stateful ones?
This is how I'm calling the Search component in the App class:
render() {
const { searchTerm, list } = this.state;
return (
<div className="App">
<Search
value = { searchTerm }
onChange = { this.onSearchChange }
>
Search
</Search>
<Table
list = { list }
pattern = { searchTerm }
onDismiss = { this.onDismiss }
/>
</div>
)
I'm not receiving an error at all, so i'm not getting much that's pointing me in the right direction, i'm hoping i'm just missing something silly.
Thanks in advance!
In both cases, it's a stateless function only as there's no state and it's not an class component either.
1st case is working correctly because it's returning the element with the return keyword.
2nd refactored case is also correct but you are not returning anything you need to return the element for it to be rendered.
return example
const func = () => {
... // any more calculations or code
return ( // you are returning the element here
<div>
...
</div>
)
}
If there's no calculation or any additional code and you have to return only an element you can directly return it by using (...) instead of {...} as follows
const func = () => ( // you are directly returning element
<div>
...
</div>
)
PS: for more info you can check into arrow functions
onclick isn't working on my react component, here is my code:
const listItems = xox.map((nums) =>
<Square key={nums.index} cont={nums.content} onclick={function (){
alert();
}}/>
);
also i tried this but alert working on the when render the page:
<Square key={nums.index} cont={nums.content} onclick={alert()}/>
my app function:
function App() {
return (
<div className="App">
<header>
<img src={logo} alt="React logo"/>
<h1>XOX</h1>
</header>
<div className="playground">
{listItems}
</div>
</div>
);
}
Square.js
import React from "react";
export class Square extends React.Component {
render() {
return (
<div className="square" onClick={this.props.onclick}>
{this.props.cont}
</div>
)
}
}
You need to make sure your Square component accepts and then uses an onclick prop. For example, something like:
const Square = ({ cont, onclick }) => (
<div onClick={onclick}>{cont}</div>
);
Otherwise the prop will be ignored, since it's not used inside the component.
also i tried this but alert working on the when render the page:
Yes, you need to pass a function as a prop, not invoke the function then pass the result as a prop. This:
return <Square key={nums.index} cont={nums.content} onclick={alert()}/>
is equivalent to doing
const result = alert();
return <Square key={nums.index} cont={nums.content} onclick={result}/>;
So you instead need
onclick={() => alert()}
(or with the function keyword as you're already doing, though it's less terse)
If possible, I'd also suggest using the standard capitalization for React click handlers, which is onClick, not onclick - there's less chance of confusing people that way.
try using arrow functions:
<Square key={nums.index} cont={nums.content} onClick={() => alert('hello world')}/>
I need to call a Component (ExampleComp), and when the button is clicked, call againthe component (ExampleComp). The idea is to call the Component(ExampleComp) as many times as you press the button.
function newComponent{
<ExampleComp/>
}
------
return(
<div>
<ExampleComp/>
<Button className="btnNew" onClick=
{newComponent}> Create a new Component</Button>
</div>
)
Actually i don't know how to do it exactly and i would apreciate your help.
You can use the state for this purpose. Let's say your state is something like this:
this.state = { items: [] };
You can render all the items like the following example:
return (
<div>
{this.state.items.map(item => {
return <ExampleComp exampleProp={item.exampleProp} />;
})}
<Button className="btnNew" onClick={newComponent}>
Create a new Component
</Button>
</div>
);
And finally, you can push an item into the state, and React will take care of the rest.
function newComponent{
newItem = { exampleProp: 'Something?' };
this.setState((state, props) => ({ items: [...items, newItem] }));
}
This will do the job. I just used "exampleProp" to be an example but you don't have to use it. Actually, the state can be just a number too. The important part is using state in every user interface change.
render(){
return (
<Button className="btnNew" onClick={ this.setState({ clicked:true }) }>Create a new Component</Button>
{
this.state.clicked ? {newComponent} : null
}
)
}
This would help but though not recommended by me as setState will re-render(load) the component again onClick.
I wrote two sample components to show what I'm trying to do.
If the call was from the same class, I could do like below.
onClick={this.myFunc.bind(this, param1, param2)}
How do I do the same thing from a stateless component without the need to mess with binding 'this'.
onClick={props.onClick['need to add params']}
import React from 'react';
class BigComponent extends React.Component{
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(param1, param2){
// do something with parameters
}
render(){
return(
<div>
<SmallComponent handleClick={this.handleClick}/>
</div>
);
}
}
function SmallComponent(props){
return(
<div>
<button onClick={ () => {props.handleClick('value_1', 'value_2')}}></button>
<button onClick={ () => {props.handleClick('value_3', 'value_4')}}></button>
{/* how to do above without arrow functions, because I read that it's not optimized*/}
</div>
);
}
Add a callback inside of this.myFunc.
this.myFunc = event => (param1, param2) => { ... do stuff }
In your top level component you can do:
handleClick={this.myFunc}
In your child, just do:
onClick={handleClick(param1, param2)}
Hope this is helps.
Alternatively you can do the following:
function SmallComponent(props){
const handleClick = (param1, param2) => (event) => props.handleClick(param1, param2);
return(
<div>
<button onClick={handleClick(param1, param2)}></button>
...
);
}
As you can see in the two components below, i want to delete the recipes(in app component) from a button click in the panelcomponent,
i have a method in app to delete the recipe, and a prop(onclick) send to child panelcomponent. Panel then gets the index from the map of recipes, and after the button click it executes the handleDelet method to send the index back to parent. but No this is not working !
class App extends React.Component {
state={
addRecipe:{recipeName:"",ingredients:[]},
recipes:[{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]}]
}
handleDelete = (index) => {
let recipes = this.state.recipes.slice();
recipes.splice(index,1); //deleting the index value from recipe
this.setState({recipes}) //setting the state to new value
console.log(index,recipes)
}
render() {
return (
<div className="container">
<PanelComponent recipes={this.state.recipes} onClick={()=>this.handleDelete(index)}/>
<ModalComponent />
</div>
);
}
}
class PanelComponent extends React.Component {
handleDelete = (index) => {
this.props.onClick(index); //sending index to parent after click
console.log(index)
}
render() {
return (
<PanelGroup accordion>
{this.props.recipes.map( (recipe,index) => {
return(
<Panel eventKey={index} key={index}>
<Panel.Heading>
<Panel.Title toggle>{recipe.recipeName}</Panel.Title>
</Panel.Heading>
<Panel.Body collapsible>
<ListGroup>
{recipe.ingredients.map((ingredient)=>{
return(<ListGroupItem>{ingredient}</ListGroupItem>);
})}
</ListGroup>
<Button bsStyle="danger" onClick={()=>this.handleDelete(index)}>Delete</Button>
<EditModalComponent />
</Panel.Body>
</Panel>
);
})}
</PanelGroup>
);
}
}
Thea actual error in your code is that while using arrow function in the onClick in parent, you are passing the wrong parameter, instead of {()=>this.handleDelete(index)} what you should write is
{(value)=>this.handleDelete(value)}, However, that also not necessary and you could simple write {this.handleDelete} in App since your handleDelete function is already binded and it received the values from the Child component.
render() {
return (
<div className="container">
<PanelComponent recipes={this.state.recipes} onClick={(value)=>this.handleDelete(value)}/>
<ModalComponent />
</div>
);
}
The difference in writing {()=>this.handleDelete(index)} vs {(value)=>this.handleDelete(value)} is that in the first case, you are explicitly passing the index that you get from the map function in your App component while in the second case, the value passed from the child component when you execute this.props.onClick(value) is being provided to the handleDelete function.
you are sending the function wrongly as props. you are sending the result of the function as props rather than the function itself
class App extends React.Component {
state={
addRecipe:{recipeName:"",ingredients:[]},
recipes:[{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]},
{recipeName:"Apple",ingredients:["apple","onion","spice"]}]
}
handleDelete = (index) => {
let recipes = this.state.recipes.slice();
recipes.splice(index,1); //deleting the index value from recipe
this.setState({recipes}) //setting the state to new value
console.log(index,recipes)
}
render() {
return (
<div className="container">
//change here
<PanelComponent recipes={this.state.recipes} onClick={this.handleDelete}/>
<ModalComponent />
</div>
);
}
}