I know this is a really basic thing, but for some reason my mind is just running a blank right now on what Im doing wrong. So basically all Im trying to do is click a button and show the value go up by 1 everytime I click it. Im trying to have my Increment button as a child and then pass the new value up to the parent.
This is my app.js (parent)
import React from 'react';
import IncrementButton from './increment-button';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment(){
this.setState({
count:this.state.count+1
})
}
render() {
return (
<div className="parent">
<div className="count">
Number of clicks: {this.state.count}
</div>
<IncrementButton count={this.increment}/>
</div>
);
}
}
This is my increment-button component
import React from 'react';
export default function IncrementButton(props) {
return <button onClick={() => props.count}>Increment</button>;
}
Right now Im not seeing any change for "Number of clicks:"
You gotto call the count() since it is a function -
<button onClick={() => props.count()}>Increment</button>;
props.count is a function, invoke it.
import React from 'react';
export default function IncrementButton(props) {
return <button onClick={() => props.count()}>Increment</button>;
}
Also for your app.js, you need to bind the scope for this.increment, so use arrow function instead.
import React from 'react';
import IncrementButton from './increment-button';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
increment(){
this.setState({
count:this.state.count+1
})
}
render() {
return (
<div className="parent">
<div className="count">
Number of clicks: {this.state.count}
</div>
<IncrementButton count={() => this.increment()}/>
</div>
);
}
}
Related
I have a Parent (Class Based Component) and a Child (Function Based Component). I need the method of function based component, when I will click on (+) Button of Parent Class Component.
I have imported child component to parent component
I can't handle the click event in here of parent component
onClick={ }
Here is my Parent Class Based Component
import React from "react";
import Increment from "./Increment";
class Timer extends React.Component {
//State
state = {
count: 0
}
render() {
return (
<div className="top">
<span className="display">{this.state.count}</span>
<button className="btn btn-primary" onClick={<Increment />} >
+
</button>
</div>
)
}
}
export default Timer
Here is my Child Function Component
import React, { Component } from "react";
class Increment extends Component {
incrementTimer = props => {
this.setState({ count: props.count + 1 })
}
}
export default Increment
I believe this article may shed some light on your issue: Lifting State Up - React Docs. I wouldn't suggest trying to update the state of Component #1 from inside Component #2.
Take the increment logic from your Increment Component and make it a method on your Parent Component. Then pass the method as a prop on the Increment Component.
In Timer.js
import React, { Component } from "react";
import Increment from "./Increment";
class Timer extends Component {
// The Constructor is necessary for adding the handleIncrement method
// State should be initialized here as well.
constructor(props) {
// super(props) is required on class based component constructors
super(props);
this.state = { count: 0 };
this.handleIncrement = this.handleIncrement.bind(this);
}
// This is the method
handleIncrement() {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div className="top">
<span className="display">{this.state.count}</span>
{/* handleIncrement is the name of the prop that will be referenced inside
the Increment.js Component. */}
{/* this.handleIncrement is the method. */}
<Increment handleIncrement={this.handleIncrement} />
</div>
);
}
}
export default Timer;
In Increment.js
import React from "react";
// Putting (props) means this component is expecting a prop when
// its been imported and used as <Increment propGoesHere={value} /> in Timer.js
const Increment = (props) => {
return (
<button className="btn btn-primary" onClick={props.handleIncrement}>
+
</button>
);
};
export default Increment;
As an aside, Class based components can be avoided altogether (because who wants to deal with the "this" keyword, constructors, and binding every method) by using the useState hook.
It would look something like:
In Timer.js
import React, { useState } from "react";
const Timer = () => {
const [count, setCount] = useState(0);
const handleIncrement = () => {
setCount(count + 1);
};
return (
<div className="top">
<span className="display">{count}</span>
<button className="btn btn-primary" onClick={handleIncrement}>
+
</button>
</div>
);
};
export default Timer;
No need for a class to hold the state anymore, now any component can house state!
No more constructor, no need to bind methods, no more "this" keyword!
No need for the entire Incremement child Component
First of all
<button className="btn btn-primary" onClick={<Increment />} >
+
</button>
This specific piece of code is impossible to make work. You cannot pass a component as a function to an onClick.
Since I do not know the practical application of your question I have no clue what is exactly you are trying to achieve so here is just an option of how to make these specific components work.
import React from "react";
import Increment from "../components/Increment";
class Timer extends React.Component {
//State
state = {
count: 0,
mountCounter: false,
};
increaseCount = () => {
this.setState({ count: this.state.count + 1, mountCounter: false });
};
render() {
return (
<div className="top">
<span className="display">{this.state.count}</span>
<button
className="btn btn-primary"
onClick={() => this.setState({ mountCounter: true })}
>
+
{this.state.mountCounter && (
<Increment increaseCount={() => this.increaseCount()} />
)}
</button>
</div>
);
}
}
export default Timer;
import React, { Component } from "react";
class Increment extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
this.props.increaseCount();
}
render() {
return null;
}
}
export default Increment;
I created a reset function in App.js and want to call it by an onclick in two other components. the problem is that it works in one component but doesn't in the other.
Here are the codes snippets
App.js
import React from 'react';
import Result from './components/Result';
import GeneralResult from './components/GeneralResult';
class App extends Component {
constructor(props) {
super(props);
this.state = {
result: '',
counter: 0,
}
}
// Reset function
handleReset=()=>{
this.setState({
result: '',
counter: 0,
)}
renderResult() {
return (
<div>
<Result reset={()=>this.handleReset()} />
<GeneralResult back={()=>this.handleReset()} />
</div>
);
}
Result.js
first component making use of reset()
function Result(props) {
return (
<div>
<span>
<button onClick={props.reset}>Replay</button>
</span>
</div>
);
}
export default Result;
GeneralResult.js
second component making use of the reset
import React, { Component } from 'react';
export default class GeneralResult extends Component {
render() {
return (
<React.Fragment>
<h2>Congratulations you won!</h2>
<span>
<button onClick={props.back}> Back to Question</button>
</span>
</React.Fragment>
);
}
}
You can pass the handler as props, and render the component from the parent class.
class Child extends Component {
render(){
return(
<button onClick = {this.props.onClick}></button>
)
}
}
export default Child;
import Child from 'path/to/child';
class Parent extends Component {
onClick = (e) => {
//do something
}
render () {
return(
<Child onClick = {onCLick}/>
)
}
}
Problem is that GeneralResult is class based component. so when you need to access props passed to it. you have to use this.props.
export default class GeneralResult extends Component {
render() {
return (
<React.Fragment>
<h2>Congratulations you won!</h2>
<span>
// you need to change "props.back"
// to "this.props.back"
<button onClick={this.props.back}> Back to Question</button>
</span>
</React.Fragment>
);
}
}
I am learning React and I am trying to call a function in a child component, that accesses a property that was passed from parent component and display it.
The props receives a "todo" object that has 2 properties, one of them is text.
I have tried to display the text directly without a function, like {this.props.todo.text} but it does not appear. I also tried like the code shows, by calling a function that returns the text.
This is my App.js
import React, { Component } from "react";
import NavBar from "./components/NavBar";
import "./App.css";
import TodoList from "./components/todoList";
import TodoElement from "./components/todoElement";
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: []
};
this.addNewTodo = this.addNewTodo.bind(this);
}
addNewTodo(input) {
const newTodo = {
text: input,
done: false
};
const todos = [...this.state.todos];
todos.push(newTodo);
this.setState({ todos });
}
render() {
return (
<div className="App">
<input type="text" id="text" />
<button
onClick={() => this.addNewTodo(document.getElementById("text"))}
>
Add new
</button>
{this.state.todos.map(todo => (
<TodoElement key={todo.text} todo={todo} />
))}
</div>
);
}
}
export default App;
This is my todoElement.jsx
import React, { Component } from "react";
class TodoElement extends Component {
state = {};
writeText() {
const texto = this.props.todo.text;
return texto;
}
render() {
return (
<div className="row">
<input type="checkbox" />
<p id={this.writeText()>{this.writeText()}</p>
<button>x</button>
</div>
);
}
}
export default TodoElement;
I expect that when I write in the input box, and press add, it will display the text.
From documentation
Refs provide a way to access DOM nodes or React elements created in the render method.
I'll write it as:
class App extends Component {
constructor(props) {
super(props);
this.state = {
todos: []
};
this.textRef = React.createRef();
this.addNewTodo = this.addNewTodo.bind(this);
}
addNewTodo() {
const newTodo = {
text: this.textRef.current.value,
done: false
};
const todos = [...this.state.todos, newTodo];
this.setState({ todos });
}
render() {
return (
<div className="App">
<input type="text" id="text" ref={this.textRef} />
<button onClick={this.addNewTodo}>Add new</button>
{this.state.todos.map(todo => (
<TodoElement key={todo.text} todo={todo} />
))}
</div>
);
}
}
In your approach, what you got as an argument to the parameter input of the method addNewTodo is an Element object. It is not the value you entered into the text field. To get the value, you need to call input.value. But this is approach is not we encourage in React, rather we use Ref when need to access the html native dom.
In the renderList(), I have a delete button that will delete the content once it is clicked. I am not sure where to put the setState so I put it inside on the onClick(). This doesn't work. I would like to know if I am doing this correct or if there is a better way to solve this.
onClick Function
onClick={() => {
this.props.deleteBook(list.book_id);
this.setState({delete: list.book_id});
}}>
React.js
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { selectUser } from '../actions/index.js';
import { deleteBook } from '../actions/index.js';
import _ from 'lodash';
class myPage extends Component {
constructor(props) {
super(props);
this.state = {
delete: 0
}
}
componentWillMount() {
this.props.selectUser(this.props.params.id);
}
renderList() {
return this.props.list.map((list) => {
return (
<li className='book-list'
key={list.book_id}>
{list.title}
<button
value={this.state.delete}
onChange={this.onClickChange}
onClick={() => {
this.props.deleteBook(list.book_id);
this.setState({delete: list.book_id});
}}>
Delete
</button>
</li>
);
})
}
render() {
const {user} = this.props;
const {list} = this.props;
if(user) {
return(
<div>
<h2>Date Joined: {user.user.joined}</h2>
<h1>My Page</h1>
<h2>Username: {user.user.username}</h2>
<div>My Books:
<h1>
{this.renderList()}
</h1>
</div>
</div>
)
}
}
}
function mapStateToProps(state) {
return {
user: state.user.post,
list: state.list.all
}
}
export default connect(mapStateToProps, { selectUser, deleteBook })(myPage);
Based on your use of mapStateToProps, seems like you are using Redux. Your list of books comes from the Redux store as props which is external to the component.
You do not need this.state.delete in the component. As state is managed by Redux, it seems like the bug is in your Redux code and not React code. Look into the reducers and ensure that you are handling the delete item action correctly.
I am starting to learn react and download and follow any tutorials in internet. I am trying to build friend list.
I have tree components,
friends_container:
import React from 'react';
import AddFriend from './add_friend.jsx'
import ShowList from './show_list.jsx'
class FriendsContainer extends React.Component {
constructor() {
this.state = {
friends: ['Jake Lingwall', 'Murphy Randall', 'Merrick Christensen']
}
}
addFriend(friend) {
this.setState({
friends: this.state.friends.concat([friend])
});
}
render() {
return (
<div>
<h3> Add your friend to friendslist </h3>
<AddFriend addNew={this.addFriend}/>
<ShowList names={this.state.friends}/>
</div>
)
}
}
export default FriendsContainer;
add_friend:
import React from 'react';
class AddFriend extends React.Component {
constructor() {
this.state = {newFriend: ''};
}
updateNewFriend(e) {
this.setState({
newFriend: e.target.value
})
}
handleAddNew() {
this.props.addNew(this.state.newFriend);
this.setState({
newFriend: ''
});
}
render() {
return (
<div>
<input type="text" value={this.state.newFriend} onChange={this.updateNewFriend}/>
<button onClick={this.handleAddNew}>Add Friend</button>
</div>
)
}
}
AddFriend.propTypes = { addNew: React.PropTypes.func.isRequired };
export default AddFriend;
show_list:
import React from 'react';
class ShowList extends React.Component {
render() {
var listItems = this.props.names.map((f, i) => <li key={i}>{f}</li>);
return (
<div>
<h3>Friends</h3>
<ul>
{listItems}
</ul>
</div>
)
}
}
ShowList.defaultProps = { names: [] };
export default ShowList;
and app.jsx
import React from 'react';
import FriendsContainer from './components/friends_container.jsx';
window.React = React;
React.render(<FriendsContainer />, document.body);
as you can see on the code, I am using es6 and babel as transcompiler.
My problem, I can not type any letters into the input field to add new friend into friends list. What am I doing wrong?
In the context of your updateNewFriend method, this refers to the window object and not the current component instance. You need to bind the method before passing it as the onChange event handler. See Function::bind.
You have two options:
class AddFriend extends React.Component {
constructor() {
// ...
this.updateNewFriend = this.updateNewFriend.bind(this);
this.handleAddNew = this.handleAddNew.bind(this);
}
}
or
class AddFriend extends React.Component {
render() {
return (
<div>
<input type="text" value={this.state.newFriend} onChange={this.updateNewFriend.bind(this)}/>
<button onClick={this.handleAddNew.bind(this)}>Add Friend</button>
</div>
)
}
}
Keep in mind that Function::bind returns a new function, so binding in render creates a function every time your component is rendered, though the performance impact is negligible.