Why I encountered is not iterable? - javascript

I have this error and I started to learn React last week so I couldn't solve the problem.
Uncaught TypeError: contacts is not iterable
at onSubmit (index.js:15:1)
Contacts Component
import List from "./List"
import Form from "./Form"
import {useState,useEffect} from "react"
import React from "react"
function Contacts(){
const [contacts,setContacts] = useState([]);
useEffect(()=>{
console.log(contacts)
},[contacts])
return (
<div>
<List/>
<Form addContact = {setContacts} contacts={contacts}/>
</div>
)
}
export default Contacts
Form Component
import React from "react"
import { useState } from "react"
function Form(addContact,contacts){
const [form,setForm] = useState({fullName : "" , phoneNumber : ""})
const onChangeInput = (event) => { setForm({...form,[event.target.name]: event.target.value}) }
const onSubmit = (event) => {
event.preventDefault();
if(form.name ==="" || form.phoneNumber===""){
return false
}
addContact([...contacts , form]);
}
return (
<form onSubmit={onSubmit}>
Form List
<div><input name="fullName" placeholder="fullName" onChange={onChangeInput}></input></div>
<div><input name="phoneNumber" placeholder="phoneNumber" onChange={onChangeInput}></input></div>
<div>
<button>Add</button>
</div>
</form>
)
}
export default Form

please use props like this
wrap with {}
function Form({ addContact, contacts }){
...
...
...
}

Related

How to scroll to a component from another component in React?

I have a form that, on submission displays the results of the form, but more importantly, scrolls to a component that shows the results. I am stuck trying to pass in refs and forward refs. All of the demos I've seen have been of components in the same file. My setup is as follows:
The App.js holds two components– Form.js which submits the form and Results.js which displays the results of the form submission. The Results.js component is further down the page so I want to scroll to that component once the user clicks enter on the form.
Here is a codesandbox that demonstrates my setup.
Here is the same code on here:
// App.js
import "./styles.css";
import Form from "./Form";
import Results from "./Results";
export default function App() {
return (
<>
<Form />
<Results />
</>
);
}
// Form.js
import { forwardRef, useState } from "react";
const Form = forwardRef(({ onScroll }, ref) => {
const [name, setName] = useState("");
const onSubmit = (e) => {
e.preventDefault();
onScroll();
};
return (
<form onSubmit={onSubmit} className="tall">
<input value={name} onChange={(e) => setName(e.target.value)} />
<button type="submit">Submit</button>
</form>
);
});
export default Form;
// Results.js
import { useRef } from "react";
export default function Results() {
const resultsRef = useRef();
function handleScrollToResults() {
resultsRef.current.scrollIntoView({ behavior: "smooth" });
}
return (
<div onScroll={handleScrollToResults}>
<h1>Results</h1>
</div>
);
}
Few things to be corrected.
Results component should forward the ref, not to the Form component.
import { forwardRef } from "react";
const Results = forwardRef((props, ref) => {
return (
<div ref={ref}>
<h1>Results</h1>
</div>
);
});
export default Results;
Form component should receive the ref to Results as a prop (resultRef).
import { useState } from "react";
const Form = ({ resultRef }) => {
const [name, setName] = useState("");
const onSubmit = (e) => {
e.preventDefault();
resultRef.current.scrollIntoView({ behavior: "smooth" });
};
return (
<form onSubmit={onSubmit} className="tall">
<input value={name} onChange={(e) => setName(e.target.value)} />
<button type="submit">Submit</button>
</form>
);
};
export default Form;
Root component should create the ref using useRef and use it as below. Notice that Form is using the resultRef while Results is instantiating it.
import "./styles.css";
import Form from "./Form";
import Results from "./Results";
import { useRef } from "react";
export default function App() {
const resultRef = useRef(null);
return (
<>
<Form resultRef={resultRef} />
<Results ref={resultRef} />
</>
);
}

Is there a way to bind the ref {useRef} to the submit function/variable

I'm new to react and I'm trying to build a form. I want the page to redirect to the home page once the form is submitted. Is there a way to set useRef to watch the in-built submit function?
I currently have no compiler errors but the page won't redirect.
current code:
import React, {useRef} from 'react'
import {useForm} from 'react-hook-form'
import Button from '#material-ui/core/Button'
import {Redirect} from 'react-router-dom'
export default function Form() {
const submit = useRef(false)
const {register, handleSubmit} = useForm();
const redir = (data) => {
console.log(submit.current)
console.log(data)
return <Redirect to='/' />
}
return (
<div>
<form className="form" ref={submit} onSubmit={handleSubmit(redir)}>
You're returning the Redirect from a handler function but you need to render it. Instead, you could use history.push('/') to do what you want.
import { useHistory } from 'react-router-dom';
//...
export default function Form() {
const submit = useRef(false);
const history = useHistory();
const {register, handleSubmit} = useForm();
const redir = (data) => {
console.log(submit.current);
console.log(data);
history.push('/');
}
return (
<div>
<form className="form" ref={submit} onSubmit={handleSubmit(redir)}>
<input type="submit" value="Submit" />
</form>
</div>
);
}

How to implement onClick componentDidMount() in React using Axios

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.

Why is my text not changing as I'm writing text to the input tag in React

My code from App.js. The idea is that when you enter text in input the screen should be updated accordingly. For some reason set state isn't working and I don't know why.
import React, { Component } from 'react';
import UserOutput from './Components/UserOutput';
import UserInput from './Components/UserInput';
class App extends Component {
state = {
username: 'Adib',
};
changeUsername = (event) => {
this.setState({
username: event.target.value,
});
};
render() {
return (
<div className="App">
<UserInput changed={this.changeUsername} />
<UserOutput name={this.state.username} />
</div>
);
}
}
export default App;
My code from useroutput.js
import React from 'react';
const userOutput = (props) => {
return (
<div>
<p>Username: {props.name}</p>
<p>Hello {props.name}</p>
</div>
);
};
export default userOutput;
My code from userinput.js
import React from 'react';
const userInput = (props) => {
return <input type="text" onChanged={props.changed} />;
};
export default userInput;
You are using onChanged as the name of the event action on the input field in the userInput Component. replace it with
return <input type="text" onChange={props.changed} />;
Your UserInput component is using an onChanged event which is not a valid event in React, try using onChange instead.
import React from 'react';
const userInput = (props) => {
return <input type="text" onChange={props.changed} />;
};
export default userInput;

You must either pass handleSubmit() an onSubmit function or pass onSubmit as a prop | Redux Forms

I want to create a simple form that takes in an email adress and later adds it to our database. I went with React Forms, because it facilitates the whole development process and reduces the amount of time.
However, when I'm trying to POST my form I'm getting this error: Uncaught Error: You must either pass handleSubmit() an onSubmit function or pass onSubmit as a prop
Here's my AddUserForm.js:
import React from 'react'
import { Field, reduxForm } from 'redux-form'
const AddUserForm = ({ handleSubmit }) => {
return (
<form onSubmit={handleSubmit}>
<div>
<Field name="email" component="input" type="email" />
</div>
<button type="submit">Bjud in</button>
</form>
)
}
export default reduxForm({
form: 'addUser'
})(AddUserForm)
Here's my addUserAction:
import axios from 'axios'
import settings from '../settings'
axios.defaults.baseURL = settings.hostname
export const addUser = email => {
return dispatch => {
return axios.post('/invite', { email: email }).then(response => {
console.log(response)
})
}
}
And here's my AddUserContainer.js:
import React, { Component } from 'react'
import { addUser } from '../../actions/addUserAction'
import AddUserForm from './Views/AddUserForm'
import { connect } from 'react-redux'
class AddUserContainer extends Component {
submit(values) {
console.log(values)
this.props.addUser(values)
}
render() {
return (
<div>
<h1>Bjud in användare</h1>
<AddUserForm onSubmit={this.submit.bind(this)} />
</div>
)
}
}
function mapStateToProps(state) {
return { user: state.user }
}
export default connect(mapStateToProps, { addUser })(AddUserContainer)
I am really grateful for all the answers! Stay awesome!
In your AddUserForm.js
Here you have to add onSubmitHandler as a prop for taking in the submit function that's suppose to run on form submit. You then have to pass the onSubmitHandler to handleSubmit()
import React from 'react'
import { Field, reduxForm } from 'redux-form'
const AddUserForm = ({ handleSubmit, onSubmitHandler }) => {
return (
<form onSubmit={handleSubmit(onSubmitHandler)}>
<div>
<Field name="email" component="input" type="email" />
</div>
<button type="submit">Bjud in</button>
</form>
)
}
export default reduxForm({
form: 'addUser'
})(AddUserForm)
In your AddUserContainer.js
Change onSubmit={this.submit.bind(this)} to onSubmitHandler={this.submit.bind(this)}
Not 100% this is your problem but I would recommend against trying to bind on the form or whatever. Assuming you're storing the input in the state's user object, then you just want to define a submit method, and call it with this.state.user. That method should basically just call your api method.
import React, { Component } from 'react'
import { addUser } from '../../actions/addUserAction'
import AddUserForm from './Views/AddUserForm'
import { connect } from 'react-redux'
class AddUserContainer extends Component {
submit(values) {
console.log(values)
this.props.addUser(values)
}
render() {
return (
<div>
<h1>Bjud in användare</h1>
<AddUserForm onSubmit={this.submit(this.state.user)} />
</div>
)
}
}
function mapStateToProps(state) {
return { user: state.user }
}
export default connect(mapStateToProps, { addUser })(AddUserContainer)

Categories