How to implement onClick componentDidMount() in React using Axios - javascript

I am trying to make a movie search function using React, Axios, and movieDB API. The functionality I am trying to implement right now is typing in a movie into the search bar and clicking the submit button will return the movie title as an H1 element.
My onClick function does not work: <button onClick={(e)=>clickHandler()}>submit</button>
componentDidMount() will work only when the page refreshes and you cannot search for anything as the submit button is broken.
I am not sure how to implement this, but I would also not mind if I could get it to search by hitting enter instead of using a button, whichever is easier.
Here is my code so far.
App.js
import React from "react"
import Movielist from './components/Movielist'
function App() {
return (
<div>
<input type="search" id="search" />
<button onClick={(e)=>clickHandler()}>submit</button>
<h1 id="title">title</h1>
<Movielist />
</div>
)
}
export default App
Movielist.js
import React from 'react';
import axios from 'axios';
export default class Movielist extends React.Component {
state = {
title: ""
}
componentDidMount() {
const API_KEY = '***********************';
const query = document.getElementById('search').value;
axios.get(`https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`)
.then(res => {
const title = res.data['results'][0]['title'];
this.setState({ title });
})
}
render() {
return (
<h1>{this.state.title}</h1>
)
}
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.render(
<App />,
document.getElementById('root')
);

import React from 'react';
import axios from 'axios';
export default class Movielist extends React.Component {
state = {
title: ""
}
clickHandler = (event) => {
if (event.keyCode === 13) {
const query = event.target.value;
const API_KEY = '***********************';
axios.get(`https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`)
.then(res => {
const title = res.data['results'][0]['title'];
this.setState({ title });
})
}
}
render() {
return (
<input type="search" id="search" onKeyDown={event => this.clickHandler(event)} />
<h1>{this.state.title}</h1>
)
}
}

You should call API to get the movie list after hitting the button, then pass the data that you've got to Movielist. Try this:
In App.js:
import React from "react"
import axios from 'axios'
import Movielist from './components/Movielist'
function App() {
const [movieList, setMovieList] = React.useState([])
const handleOnSubmit = () => {
const API_KEY = '***********************';
const query = document.getElementById('search').value;
axios.get(`https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`)
.then(res => {
const title = res.data['results'][0]['title'];
setMovieList(res.data['results'])
})
}
return (
<div>
<input type="search" id="search" />
<button onClick={handleOnSubmit}>submit</button>
<h1 id="title">title</h1>
<Movielist movieList={movieList}/>
</div>
)
}
export default App
In Movielist.js:
import React from 'react';
const Movielist = ({movieList}) => {
return (
<div>
{
movieList.map(movie => <h1 key={movie.key}>{movie.title}</h1>)
}
<div/>
)
}
}
export default Movielist

import React, {useState} from "react"
import axios from 'axios';
import Movielist from './components/Movielist'
const [title, setTitle] = useState("")
const API_KEY = '***********************'
function App() {
const clickHandler = () => {
const query = document.getElementById('search').value;
axios.get(`https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`)
.then(res => {
const title = res.data['results'][0]['title'];
setTitle(title);
})
}
return (
<div>
<input type="search" id="search" />
<button onClick={clickHandler}>submit</button>
<h1 id="title">title</h1>
<Movielist title={title} />
</div>
)
}
export default App
just move call api handle to your onclik func then pass title props to movie list

If you want to query the API after user push submit button. You should put your call to API in the call handler, then pass the state from App to MovieList as props
export class App extends React.Component {
state = {
title: ""
}
clickHandler() {
const API_KEY = '***********************';
const query = document.getElementById('search').value;
axios.get(`https://api.themoviedb.org/3/search/movie?api_key=${API_KEY}&query=${query}`).then(res => {
const title = res.data['results'][0]['title'];
this.setState({ title });
});
}
render() {
return (
<div>
<input type="search" id="search" />
<button onClick={(e)=>clickHandler()}>submit</button>
<h1 id="title">title</h1>
<Movielist list={this.state.title}/>
</div>
)
}
}
export class MovieList extends React.Component {
render() {
<h1>{this.props.title}</h1>
}
}
Alternatively, you can wrap the input in a element and use onSubmit + evt.preventDefault() instead, by doing so you can handle button click and pressing "Enter" to submit.

Related

React not rendering the array

I am new to react and trying to create a simple todo list to understand React states and props but cant seem to understand why its not rendering the array on the screen. When the button is pressed it console logs the array of the inputs so I know that works.
here is each component currently there are no errors just nothing shows up.
App.js:
import React from "react";
import ControlPanel from "./ControlPanel";
import TodoList from "./TodoList";
class App extends React.Component {
state = { TodoList: [] };
addTask = (todoItem) => {
this.setState({ TodoList: [...this.state.TodoList, todoItem] });
console.log(this.state.TodoList);
};
render() {
return (
<div>
<ControlPanel addTask={this.addTask} />
<TodoList todoitem={this.state.TodoList} />
</div>
);
}
}
export default App;
ControlPanel.js:
import React from "react";
class ControlPanel extends React.Component {
state = { todoItem: "" };
addItem = (event) => {
event.preventDefault();
this.props.addTask(this.state.todoItem);
};
render() {
return (
<div className="ui card">
<div className="ui input">
<input
onChange={(e) => {
this.setState({ todoItem: e.target.value });
}}
value={this.state.todoItem}
type="text"
placeholder="Todo List Item"
/>
</div>
<div>
<button onClick={this.addItem} className="ui button">
Add Item
</button>
</div>
</div>
);
}
}
export default ControlPanel;
TodoList.js:
import React from "react";
import TodoItem from "./TodoItem";
const TodoList = (props) => {
const todoItems = props.TodoList?.map((todo) => {
return <TodoItem TodoItem={TodoItem} />;
});
return <div>{todoItems}</div>;
};
export default TodoList;
TodoItem.js
import React from "react";
const TodoItem = (props) => {
return <div>{this.props.TodoItem}</div>;
};
export default TodoItem;
import React from "react";
import TodoItem from "./TodoItem";
const TodoList = (props) => {
const todoItems = props.TodoList?.map((todo,idx) => {
return <TodoItem TodoItem={todo} key={idx} />; // idx or any unique key
});
return <div>{todoItems}</div>;
};
export default TodoList;
More information for key
https://reactjs.org/docs/lists-and-keys.html

Proper use of useNavigate() function in Reactjs

I'm very new to react and don't understand quite all of the restrictions yet. I'm trying to do a simple page switch after a button is clicked. After researching I figured useNavigate() would be used best for this situation. After trying to implement it into my code I realized what I had, did absolutely nothing. My goal is to send the user to a home page once the register button is clicked. As of right now, when I click the button nothing happens. This could be some small detail I missed or just me being completely oblivious. Please let me know if you think you see anything of importance, thanks in advance.
Here is my apps main page with my path being src/components/login/register:
import React from "react";
import "react-datepicker/dist/react-datepicker.css";
import { useNavigate } from "react-router-dom";
import axios from 'axios';
const api = axios.create({
...
})
const sendDetailsToServer = (payload) => {
...
}
const GoToLogin = () => {
let navigate = useNavigate();
navigate('/home');
}
export class Register extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onInputchange = this.onInputchange.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
onInputchange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
onSubmitForm() {
let registerInfo = {
user_name : this.state.username,
password : this.state.password,
email_id : this.state.email
}
sendDetailsToServer(registerInfo);
GoToLogin();
}
render() {
return (
<div className="base-container" ref={this.props.containerRef}>
<h1>Welcome!</h1>
<link rel="stylesheet" href="" />
<div className="header">Please Enter Your Account Information</div>
<div className="content">
...
<div className="footer">
<button type="button" className="btn" onClick={this.onSubmitForm}>
Register
</button>
</div>
<div className="footer-fill"></div>
</div>
);
}
}
Here is my home page found under my path src/components/login/home:
import React from "react";
const Home = () => {
return(
<div>
<h1>Login</h1>
</div>
);
};
export default Home;
useNavigate hook is added to version 6, and it can be used only in functional component. If you want to use it in class component, create a HOC(withRouter).
import { useNavigate } from "react-router-dom";
export const withRouter = (Component) => {
const Wrapper = (props) => {
const navigate = useNavigate();
return <Component navigate={navigate} {...props} />;
};
return Wrapper;
};
and use it in your register.js like this
export default withRouter(Register)
here is the complete code.
import React from "react";
import "react-datepicker/dist/react-datepicker.css";
import axios from 'axios';
const api = axios.create({
...
})
const sendDetailsToServer = (payload) => {
...
}
class Register extends React.Component {
constructor(props) {
super(props);
this.state = {};
this.onInputchange = this.onInputchange.bind(this);
this.onSubmitForm = this.onSubmitForm.bind(this);
}
onInputchange(event) {
this.setState({
[event.target.name]: event.target.value
});
}
onSubmitForm() {
let registerInfo = {
user_name : this.state.username,
password : this.state.password,
email_id : this.state.email
}
sendDetailsToServer(registerInfo);
this.props.navigate('/home');
}
render() {
return (
<div className="base-container" ref={this.props.containerRef}>
<h1>Welcome!</h1>
<link rel="stylesheet" href="" />
<div className="header">Please Enter Your Account Information</div>
<div className="content">
...
<div className="footer">
<button type="button" className="btn" onClick={this.onSubmitForm}>
Register
</button>
</div>
<div className="footer-fill"></div>
</div>
);
}
}
export default withRouter(Register)
sample code

React Props for Handle Change not a Function

I'm getting props.handleChange is not a function when running the following code. I'm trying to update the state when the checkbox is clicked. The field that is check box is called myNetwork. I thought that when NetworkArray component, which is a parent of Card component, would have access to the functions and state in App? But this is my first React App. Please, what am I doing wrong?
App.JS
import React, {Component} from 'react';
import SignUp from './components/SignUp';
import NetworkArray from './components/NetworkArray';
import {network} from './NetworkData'
import './App.css';
import 'tachyons';
class App extends Component {
constructor() {
super()
this.state = {
network: network,
}
this.handleChange=this.handleChange.bind(this);
}
handleChange(id) {
this.setState(prevState => {
const updatedNetwork = prevState.network.map(netw => {
if (netw.id===id) {
netw.myNetwork = !netw.myNetwork
}
return netw
})
return {
network:updatedNetwork
}
})
}
render() {
return (
<div>
<NetworkArray
network={network}
handleChange = {this.handleChange} />
</div>
);
}
}
export default App;
Card.js
import React from 'react';
const Card = (props) => {
return(
<div className = 'bg-light-green dib br3 pa3 ma2 grow shadow-5'>
<div>
<h3>{props.name}</h3>
<p>{props.company}</p>
<p>{props.phone}</p>
<p>{props.email}</p>
<p>{props.city}</p>
</div>
<div>
MyNetwork
<input
type = "checkbox"
checked={props.myNetwork}
onChange={()=> props.handleChange(props.id)}
/>
</div>
</div>
)
}
export default Card;
NetworkArray.js
import React, {Component} from 'react';
import Card from './Card';
const NetworkArray = ({network}) => {
const cardComponent = network.map((user,i) => {
return(
<Card
key = {network[i].id}
name = {network[i].firstName + ' ' + network[i].lastName}
company = {network[i].company}
phone= {network[i].phone}
email={network[i].email}
city = {network[i].city}
/>
)
})
return (
<div>
{cardComponent}
</div>
)
}
export default NetworkArray;
You passed the function from App component to NetworkArray component, but not to Card component.
const NetworkArray = ({network, handleChange}) => {
...
<Card
handleChange={handleChange}
...
/>
}

onchange input and set state not working?

I'm working on simple form element using react-js.
There are three component:
App
TakeInput
Index
problem is when user put text in input field setState() function not work properly and data not updated. For testing purpose when i'm placing console.log in app js component it shows undefined on console. anyone sort this please. I want to console the updated data when state update
App.js
import React, { Component } from 'react';
import InputField from './TakeInput';
class App extends Component {
state = {
userInp : '',
outText : ''
}
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}))
console.log(this.userInp);
}
render() {
return (
<div className="App">
<InputField changingVal={this.handlechanger2}/>
</div>
);
}
}
export default App;
TakeInput.JS
import React, { Component } from 'react';
class TakeInput extends Component{
state={
txt: ''
}
handlerChange = (e)=>{
const { changingVal } = this.props;
const v = document.getElementById("userInput").value;
changingVal(v);
// console.log(e.target.value);
this.setState({ txt: e.target.value })
}
render(){
return(
<input type="text" name="userInput" id="userInput" placeholder="Please Enter Text" onChange={this.handlerChange} value={this.txt}/>
)
}
}
export default TakeInput;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
it is about you are developing wrong way. I think you text input should be at your parent component
To read from state you should use this.state.abc
import React, { Component } from 'react';
class TakeInput extends Component{
handlerChange = (e)=>{
this.props.onChange(e.target.value);
}
render(){
return(
<input type="text" name="userInput" placeholder="Please Enter Text" onChange={this.handlerChange} value={this.props.txt}/>
)
}
}
export default TakeInput;
import React, { Component } from 'react';
import InputField from './TakeInput';
class App extends Component {
state = {
userInp : '',
outText : ''
}
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}))
console.log(this.state.userInp);
}
render() {
return (
<div className="App">
<InputField txt={this.state.userInp} onChange={this.handlechanger2}/>
</div>
);
}
}
export default App;
You're trying to console.log this.userInp. It should be this.state.userInp.
Also to see the update right after the last set state, you can do the following:
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}), function(){ console.log(this.state.userInp);}) // set a callback on the setState
}

React Redux cant get reducer to pick up actions

I've been learning redux & react and am building a todo list. I've been reading and looking at different articles but cant figure out what I'm missing in my setup.
Currently you can add a todo via the input. On pushing enter it sends a addTodo action with the todo text.
I'm expecting the reducer to see the action type and update the state but it never does. What am I missing?
index.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import reducer from './reducer.js';
import TodoList from './containers/container.js';
const store = createStore(reducer);
ReactDOM.render(
<Provider store={store}>
<TodoList />
</Provider>,
document.getElementById('app'));
actions.js
var uuid = require('node-uuid');
export function addTodo(text) {
console.log('action addTodo', text);
return {
type: 'ADD_TODO',
payload: {
id: uuid.v4(),
text: text
}
};
}
TodoListComponent.jsx
import React from 'react';
import TodoComponent from './TodoComponent.jsx';
import { addTodo } from '../actions/actions.js'
export default class TodoList extends React.Component {
render () {
const { todos } = this.props;
return (
<div>
<input type='text' placeholder='Add todo' onKeyDown={this.onSubmit} />
<ul>
{todos.map(c => (
<li key={t.id}>
<TodoComponent todo={t} styleName='large' />
</li>
))}
</ul>
</div>
)
}
onSubmit(e) {
const input = e.target;
const text = input.value;
const isEnterKey = (e.which === 13);
if (isEnterKey) {
input.value = '';
addTodo(text);
}
}
}
TodoComponent.jsx
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './style.css';
export default class TodoComponent extends React.Component {
render () {
const { todo } = this.props;
return (
<div styleName='large'>{todo.text}</div>
)
}
}
export default CSSModules(TodoComponent, styles);
container.js
import { connect } from 'react-redux';
import TodoList from '../components/TodoListComponent.jsx';
import { addTodo } from '../actions/actions.js';
const mapStateToProps = (state) => {
return {
todos: state
}
};
const mapDispatchToProps = (dispatch) => {
return {
addTodo: text => dispatch(addTodo(text))
}
};
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
reducer.js
import { List, Map } from 'immutable';
const init = List([]);
export default function(todos = init, action) {
console.log('reducer action type', action.type);
switch(action.type) {
case 'ADD_TODO':
console.log('ADD_TODO');
return todos.push(Map(action.payload));
default:
return todos;
}
}
In your TodoListComponent you are importing your actions directly from your actions file, but in fact you want to use the action that you map to dispatch and pass as property in the container. That explains why you see logs from the actions, but not from reducer, as the action is never dispatched to the store.
So your TodoListComponent should be:
import React from 'react';
import TodoComponent from './TodoComponent.jsx';
export default class TodoList extends React.Component {
render () {
const { todos } = this.props;
return (
<div>
<input type='text' placeholder='Add todo' onKeyDown={this.onSubmit} />
<ul>
{todos.map(c => (
<li key={t.id}>
<TodoComponent todo={t} styleName='large' />
</li>
))}
</ul>
</div>
)
}
onSubmit(e) {
const input = e.target;
const text = input.value;
const isEnterKey = (e.which === 13);
if (isEnterKey) {
input.value = '';
this.props.addTodo(text);
}
}
}
import React from 'react';
import TodoComponent from './TodoComponent.jsx';
export default class TodoList extends React.Component {
render () {
const { todos } = this.props;
return (
<div>
<input type='text' placeholder='Add todo' onKeyDown={this.onSubmit.bind(this)} />
<ul>
{todos.map(c => (
<li key={t.id}>
<TodoComponent todo={t} styleName='large' />
</li>
))}
</ul>
</div>
)
}
onSubmit(e) {
// use the addTodo passed via connect
const { addTodo } = this.props;
const input = e.target;
const text = input.value;
const isEnterKey = (e.which === 13);
if (isEnterKey) {
input.value = '';
addTodo(text);
}
}
}

Categories