I am following this tutorial React Tutorial
Here is the thing:
I am calling function createTask from create-todo.js;
the function is defined in app.js
app.js
import React from 'react';
import ToDosList from './todos-list';
import CreateToDoItem from './create-todo-item'
const todoitems=[
{
task: 'finish react todo tutorial',
isCompleted: false
},
{
task: 'eat lunch',
isCompleted: true
}
];
export default class App extends React.Component
{
constructor(props){
super(props)
this.state={
todoitems
};
}
render()
{
return(
<div>
<h1>React Demo App - ToDos </h1>
<CreateToDoItem createtask ={this.createTask.bind(this)}/>
<ToDosList
todoitems={this.state.todoitems}
/>
</div>
);
}
createTask(task)
{
//alert('called');
this.state.todoitems.push({
task,
isCompleted:false
});
this.setState({todoitems: this.state.todoitems});
}
}
create-todo.js
import React from 'react';
import App from './app';
export default class CreateToDoItem extends React.Component
{
render()
{
return(
<form onSubmit={this.handleCreate.bind(this)}>
<input type="text" placeholder="what do I need to do?" ref="createInput"/>
<button>Create</button>
</form>
);
}
handleCreate(event)
{
event.preventDefault();
//alert('called');
this.props.createTask(this.refs.createInput.value); //this throws error
}
}
I am absolutely new to React.js. I don't know how this works. Should the function be available to create-todo.js? The code is exactly how it is shown in the tutorial.
Reason is, you are passing the function in props by a different key and using inside child by a different key.
Actual function name: createTask
Passing in props by key: createtask
Using inside child by: createTask
so use this.props.createtask() instead of this.props.createTask()
Your prop is named "createtask". You should probably change your prop name to createTask (as opposed to changing references to this.props.createtask).
You could do like this:
import React from 'react';
import ToDosList from './todos-list';
import CreateToDoItem from './create-todo-item'
const items = [
{
task: 'finish react todo tutorial',
isCompleted: false
},
{
task: 'eat lunch',
isCompleted: true
}
];
export default class App extends React.Component {
state = {
todoitems: items,
taskItem: ''
}
handleChange = (e) => {
this.setState({
taskItem: e.target.value
})
}
handleCreate = () => {
e.preventDefault()
item = {
task: taskItem,
isCompleted: false // default value
}
this.setState({
todoitems: [...this.state.todoitems, item ]
})
}
render() {
return (
<div>
<h1>React Demo App - ToDos </h1>
<CreateToDoItem
handleChange={this.handleChange}
handleCreate={this.handleCreate}
taskItem={this.state.taskItem}
/>
<ToDosList todoitems={this.state.todoitems}
/>
</div>
);
}
}
Then your form will be:
import React from 'react';
import App from './app';
export const CreateToDoItem = (props) => (
<form onSubmit={props.handleCreate}>
<input type="text" placeholder="what do I need to do?"
onChange={props.handleChange}
value={props.taskItem} />
<button type='submit'>Create</button>
</form>
);
I hope it help you :)
Kindly,
Related
Im trying to simply create a search and results feature for an app. The value of the input should reflect the components listed in the CardList Array. The filter doesn't seem to update the CardList. I've logged steps along the way and I've come to the conclusion that its the filter I set up. I cant seem to figure out why it wont filter the list.
import React, {Component} from 'react';
import CardList from './CardList';
import {robots} from './robots';
import './index.css';
class App extends Component {
constructor() {
super()
this.state = {
robots: robots,
searchfield: ''
}
}
onSearchChange = (event) => {
this.setState({ searchfield: event.target.value });
}
render() {
const filteredRobots = this.state.robots.filter(robot => {
return robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase());
});
return (
<div className="appAlign">
<h1 className="appTitle">RoboFriends</h1>
<input
className="searchBox"
type="search"
placeholder="Search Robots"
onChange={this.onSearchChange}
/>
<CardList robots={filteredRobots} />
</div>
);
}
}
export default App;
The error is not caused by the filter function as I have tested it and it works. It most probably lies with the robots data-set. I have slightly modified the filter function here.
import React, { Component } from "react";
import CardList from "./CardList";
import { robots } from "./robots";
class App extends Component {
constructor() {
super();
this.state = {
robots: robots,
searchfield: ""
};
}
onSearchChange = event => {
this.setState({ searchfield: event.target.value });
};
render() {
const filteredRobots = this.state.robots.filter(robot =>
robot.name.toLowerCase().includes(this.state.searchfield.toLowerCase())
);
return (
<div className="appAlign">
<h1 className="appTitle">RoboFriends</h1>
<input
className="searchBox"
type="search"
placeholder="Search Robots"
onChange={this.onSearchChange}
/>
<CardList robots={filteredRobots} />
</div>
);
}
}
export default App;
I have made a sandbox with your code which has a sample robots data and a Card that renders the filtered data-set. Take a look.
I want to make an app so that when text is typed in input element this will reflect that change in output. So far the updating doesn't work :(
import React, { Component } from 'react';
import './App.css';
import UserInput from './UserInput/UserInput';
import UserOutput from './UserOutput/UserOutput';
class App extends Component {
state = {
user: [
{ username: 'Kai' },
{ username: 'Orange' }
]
}
inputChangeHandler = (e) => {
this.setState(
{
user: [
{ username: e.target.value },
{ username: e.target.value }
]
}
)
}
render() {
return (
<div className="App">
<UserInput onChange={this.inputChangeHandler} />
<UserOutput username={this.state.user[0].username} />
<UserOutput username={this.state.user[1].username} />
</div>
);
}
}
export default App;
Change in text typed in input element should be reflected as username rendered in UserOutput. This doesn't work.
Here are codes for other components...
import React, { Component } from 'react';
class UserInput extends Component
{
render() {
return(
<div>
<input />
</div>
);
}
}
export default UserInput;
and
import React, { Component } from 'react';
class UserOutput extends Component
{
render() {
return(
<div>
<p>First paragraph and my name is {this.props.username}</p>
<p>Second paragraph </p>
</div>
);
}
}
export default UserOutput;
Ok there's your problem. You're not assigning the change handler to the input element in your UserInput component. It should be:
<input onChange={this.props.onChange} />
I am writing a react application that outputs a list of books (image, title, category, and description).
My search bar and booklist are sibling components and the search bar will pass data to the booklist.
when clicking the search button, only "Sample Category" shows up but not anything else. There is no problem accessing the API and the data is not null.
Here is a sample API output: https://www.googleapis.com/books/v1/volumes?q=lordoftherings
My code is the following:
// App
import React, { Component } from 'react';
import Axios from 'axios';
import './App.css';
import SearchBar from './SearchBar';
import BookList from './BookList';
class App extends Component {
constructor(props) {
super(props);
this.state = {
books: []
};
this.search = this.search.bind(this);
}
search(title) {
const promise = Axios.get('https://www.googleapis.com/books/v1/volumes?q=' + title);
promise.then((response) => {
const books = response.data.items;
this.setState({ books: books });
console.log(this.state.books);
})
};
render() {
return (
<div className="App">
<SearchBar searchBooks = {this.search}/>
<BookList booklist = {this.state.books}/>
</div>
);
}
}
export default App;
// Search Bar
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class SearchBar extends Component {
constructor(props) {
super(props);
this.state = { titleToSearch: 'harry potter' }
this.handleInputChange = this.handleInputChange.bind(this);
}
handleInputChange(e) {
this.setState({ titleToSearch: e.target.value });
};
render() {
return (
<form>
<input
type="text"
name="booksInput"
placeholder="Enter book title"
value={this.state.titleToSearch}
onChange={this.handleInputChange}
/>
<button type="button" onClick={() => this.props.searchBooks(this.state.titleToSearch)}>Search</button>
</form>
);
}
}
export default SearchBar;
// BookList
import React, { Component } from 'react';
class BookList extends Component {
render() {
const books = this.props.booklist;
return (
<div className="table">
{books.map((book) => {
console.log(book.id);
return (
<div className="box" key={book.id}>
<div className="img"><img src="assets/default-placeholder.jpg" alt="" /></div>
<div className="title">{book.title}</div>
<div className="category">Sample Category</div>
<div className="description">{book.description}</div>
</div>
);
})}
</div>
);
}
}
export default BookList;
In the sample code you provided, you're not actually dynamically outputting categories.
You've hard coded 'Sample category' in there.
book.category
...is not actually in the dataset.
There are categories which seem to be available under:
<div className="category">{book.volumeInfo.categories[0]}</div>
although you'll want to check if the array has length, and probably map or join each item in array to string.
just to be clear: the issue with your other fields is also that they're children of "volumeInfo"
I intend to create a to-do list without using ref as in the many examples, but it isn't working.
The expected behavior is that upon entering an entry, it will show up at the top and upon clicking add, it will create an input box for entering an entry. Currently, upon entering the state returns undefined.
The code can be found below or in this sandbox:
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import ToDo from './todo'
class App extends Component {
constructor() {
super();
this.state = {
todos: []
};
}
onChange=(e)=>{
const newToDos = [...this.state.todos]
newToDos.push(e.target.value)
this.setState({
todos: newToDos
})
}
onAdd=(e)=>{
e.preventDefault();
const newtodos=[...this.state.todos]
this.setState({
todos: newtodos.push("")
})
}
render() {
console.log(this.state.todos)
return (
<div>
<p>All the to-dos include {this.state.todos}</p>
<ToDo
todos={this.state.todos}
/>
<form onSubmit={this.onChange}>
<input
type="text"
placeholder="add a new todo..."
/>
</form>
<button onClick={this.onAdd}>+</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
And here is the todo.js:
import React, { Component } from 'react';
import { render } from 'react-dom';
export default class ToDo extends Component {
constructor(props){
super(props)
}
render() {
const {todos, onChange}=this.props
return (
<div>
{
todos.map((todo, index)=>
<div>
{todo}
</div>
)
}
</div>
);
}
}
You can store your new todo in state when onChange input and add this into todos when click save.
I have forked and edit your sample.
https://stackblitz.com/edit/react-nwtp5g?file=index.js
BTW: In your sample, newtodos.push("") will return the length of newtodos array, not the array after pushed.
onAdd=(e)=>{
e.preventDefault();
const newtodos=[...this.state.todos]
this.setState({
todos: newtodos.push("")
})
Hope this help.
your code newtodos.push("") dosent return array so no map function:
this.setState({
todos: newtodos.push("")
})
correct it something like this
this.setState({
todos: newtodos.concat("new value")
})
You have a problem with this code,
<form onSubmit={this.onChange}>
<input
type="text"
placeholder="add a new todo..."
/>
</form>
Here you are adding onSubmit on form, which will never call because you don't have submit button.
you should do something like this,
<form>
<input
type="text"
placeholder="add a new todo..."
onChange={this.onChange}
value={this.state.currentValue}
/>
</form>
onChange=(e)=>{
event.preventDefault();
this.setState({
currentValue: e.target.value
})
}
onAdd=(e)=>{
e.preventDefault();
const newToDos = [...this.state.todos]
newToDos.push(this.state.currentValue)
this.setState({
todos: newToDos,
currentValue: ''
})
}
Demo
Update
In your todo component you have useless constructor, If you don't have state in a component or don't have any function to bind this don't add constructor.
You can remove the constructor.
Another thing is, you are not passing any onChange prop to todo component, so here you will get undefined for onChange.
const {todos, onChange}=this.props
You can also write this component as a functional component.
You can update your code with
import React, { Component } from 'react';
import { render } from 'react-dom';
import './style.css';
import ToDo from './todo'
class App extends Component {
constructor() {
super();
this.state = {
todos: [],
inputText: ""
};
}
onAdd= () => {
this.setState({
todos: [...this.state.todos, this.state.inputText], textInput: ""
})
}
render() {
console.log(this.state.todos)
return (
<div>
<p>All the to-dos include {this.state.todos}</p>
<ToDo
todos={this.state.todos}
/>
<form>
<input
type="text"
placeholder="add a new todo..."
onChange={inputText => this.setState({inputText})}
/>
</form>
<button onClick={this.onAdd}>+</button>
</div>
);
}
}
render(<App />, document.getElementById('root'));
And in todo.js you can simply do
import React, { Component } from 'react';
import { render } from 'react-dom';
export default const ToDo = ({todos}) => {
return(<div>
{todos.map((todo, index) => (
<div key={index}>
{todo}
</div>))}
</div>)}
as it do not contains any state associated with it.
I need some help building a todo list with React. Im a beginner so there are a lot of aspects of react I don't understand. I've created a Todo list at the moment this lists an un ordered list with the input, edit and remove button a select menu and a further input field.
Firstly Im confused to where I update my state. the "App.js" is where my main state is stored and im trying to keep it that way. I need to know how to edit the input field (todo listitem) which stores the new value. Im then looking to create a "completed list" where i want to store the input field as well as the select option (which ever is clicked) Please could someone give me some guidelines for this. Thank you in advance
import React, { Component } from 'react';
import Form from './Components/Form'
import './App.css';
import List from './Components/List'
import Completed from './Components/Completed'
class App extends Component {
constructor(props){
super(props)
this.state={
isEditing:false,
text:"",
items:[],
completed:[
{
}
]
}
this.submit=this.submit.bind(this);
this.eventHandler=this.eventHandler.bind(this)
}
submit=(e)=>{
e.preventDefault();
this.setState({
items:[
{
name:this.state.text,
},
...this.state.items
],
text:""
})
}
remove=(index)=>{
this.setState({
items:this.state.items.filter((_,i) => i!==index)
})
}
onChange=(index)=>{
this.setState({
items:this.state.items.filter((_,i) => i!==index)
});
}
eventHandler=(e)=>{
this.setState ({
text:e.target.value
})
}
handleNameEdits=()=>{
this.setState({
isEditing:true
})
}
edit=()=>{
this.setState({
isEditing:!this.state.isEditing
})
}
myoptions=(e)=>{
this.setState({
completed:[
{
webmaster:e
},
...this.state.completed
]
})
}
render() {
return (
<div className="App">
<header className="App-header">
<Form submit={this.submit} myValue={this.state.text} eventHandler=
{this.eventHandler}/>
{this.state.items.map && this.state.items.map((item,index)=>(
<List key={index}
name={item.name}
edit={this.edit}
change={()=>this.onChange(index)}
remove={()=>this.remove(index) }
handleNameEdits={this.handleNameEdits}
myoptions={(e =>this.myoptions(e.target.value))}
/>
))}
</header>
<div>
completed
</div>
</div>
);
}
}
export default App;
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Edit from './Edit';
class List extends Component {
constructor(props) {
super()
this.options = [
{name:'web1'},
{name:'web2'},
{name:'web3'},
{name:'web4'}
];
}
render() {
const {key} = this.props;
const x=this.options;
return (
<ul>
<li>{this.props.name}
<button onClick={this.props.edit}>Edit</button>
<button onClick={this.props.remove}>Remove</button>
<select onChange={this.props.myoptions}>
{this.options.map(options => <option>{options.name}</option> )}
</select>
<label> Completed
</label><input type="checkbox" onChange=
{this.props.change} checked={this.props.change} onClick=
{this.props.submit}/>
<label> Ticket Number </label><input type='text'/>
</li>
</ul>
)
}
}
export default List;
import React from 'react'
import PropTypes from 'prop-types';
const Form= props=> {
return (
<form onSubmit={props.submit}>
<input type='text' value={props.myValue} onChange=
{props.eventHandler}/>
<button> click</button>
</form>
)
}
Form.PropTypes={
onSubmit:PropTypes.func.isRequired,
evenHandler:PropTypes.func.isRequired,
myValue:PropTypes.string.isRequired
}
export default Form