passing an event to a child component in React - reactjs

I'm new to React and this is a very noob question, but I don't understand why this is not working.
I'm trying to build a simple todo List.
My TodoList.js Component looks like this:
import React, {Component} from 'react';
import TodoItem from './TodoItem';
export default class TodoList extends Component{
constructor(props){
super(props);
this.state = {
todos:[
{
title:"todo1"
},
{
title:"todo3"
},
{
title:"todo2"
}
]
}
}
handleRemove(idx){
alert('works');
}
render(){
var todos = this.state.todos.map(function(t,idx){
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
})
return (
<div>
<h1>To do</h1>
<div>{todos}</div>
</div>
)
}
}
My child Component looks like this:
import React, {Component} from 'react';
export default class TodoItem extends Component{
render(){
return (
<div>{this.props.title}
<button onClick={this.props.remove}>X</button>
</div>
)
}
}
But I get a TypeError with "Cannot read property 'handleRemove' of undefined". I'm wondering why inside the map function {this} is undefined?
I tried to put this this.handleRemove = this.handleRemove.bind(this) into the constructor.
Didn't change anything. Shouldn't this also be defined inside the .map() ?

You need to put this as the second argument
If a thisArg parameter is provided to map, it will be used as
callback's this value. Otherwise, the value undefined will be used as
its this value. The this value ultimately observable by callback is
determined according to the usual rules for determining the this seen
by a function.
on map:
render(){
var todos = this.state.todos.map(function(t,idx){
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
}, this)
return (
<div>
<h1>To do</h1>
<div>{todos}</div>
</div>
)
}
}
Alternatively, you can use an ES6 arrow function to automatically preserve the current this context:
var todos = this.state.todos.map((t,idx) => {
return(<TodoItem
remove={this.handleRemove.bind(this,idx)}
title={t.title}
/>)
})

Related

How to update render() of a class-base component using onChange method of an input

I have written these to components that are going to search through a JSON file.
The first component consists of two parts 1-it returns elements of JSX representing and 2-it finds matches through the JSON file and fills the data in a Const and passes that to props of the other component which is created to show the results.
The problem is that the render() method of the component does not reload the newly entered data whereas variables work properly and data is passed from the first component to the second one without any problem.
import react from 'react';
import React, { Component } from 'react';
import './index.css';
import ResultP from './ResultP';
import userData from './userData';
class SearchP extends Component {
constructor(props){
super(props);
this.state = {
SearchValue : "",
MatchingItems : []
}
}
handleChange = (word)=> {
const match = word.target.value;
const Matches = userData.filter((users) => {return users.name.includes(match);});
this.setState({MatchingItems : Matches})
console.log(this.state.MatchingItems);
};
render() {
return (
<div>
<form className="my-form" >
<input type="search" onChange={this.handleChange}
placeholder="Write your keyword here" />
</form>
<ResultP SearchString = {this.state.MatchingItems} />
</div>
)
}
}
export default SearchP;
this one was the first component.
Below is the second one
import React, { Component } from 'react';
class ResultP extends Component {
constructor(props){
super (props);
this.state = {
SearchString : this.props.SearchString,
}
}
render() {
return (
<section className="main-section">
{this.state.SearchString}
</section>
)
}
}
export default ResultP;
The constructor logic only executes once when the component is initially rendered, so when you initialize a state variable in the constructor with a prop value, that state variable won't update if the prop value changes. You'll need to add the getDerivedStateFromProps function in your child component: https://reactjs.org/docs/react-component.html#static-getderivedstatefromprops. Here's an example: https://www.tutorialspoint.com/reactjs-getderivedstatefromprops-method

'Items' is not defined error when passing value to another component

I am getting ./src/App.js Line 27: 'Items' is not defined react/jsx-no-undef
while trying to pass state to a another component
import React, { Component } from 'react';
import axios from 'axios'
class App extends Component {
// Added this:
constructor(props) {
super(props);
// Assign state itself, and a default value for items
this.state = {
items: []
};
}
componentWillMount() {
axios.get('https://api.opendota.com/api/proMatches').then(res => {
this.setState({ items: res.data });
});
}
render() {
return (
<div className="app">
<Items items={this.state.items} />
</div></blink></blink>
);
}
}
export default App;
You are not trying to use a component called Items without importing it first:
<Items items={this.state.items} />
Every component that you use must be imported first:
import { Items } from "DIRECTORY"
Errors:- (1) import Items component (2) use componentDidMount() instead of componentWillMount() (3) use ternary operator in JSX this.state.items.length > 0 for displaying items after getting response
import React, { Component } from 'react';
import axios from 'axios';
import Items from './Items';
class App extends Component {
// Added this:
constructor(props) {
super(props);
// Assign state itself, and a default value for items
this.state = {
items: []
};
}
componentDidMount() {
axios.get('https://api.opendota.com/api/proMatches').then(res => {
this.setState({ items: res.data });
});
}
render() {
return (
<div className="app">
{
this.state.items.length > 0 ?
<Items items={this.state.items} /> : null
}
</div></blink></blink>
);
}
}
export default App;
App is top component and Items is child component.To use any child component or pass any kind props or state ,it has to be imported first .
There can be another issue to it since you are using state and if the child component Items is rerendered due to any change ,then state of your APP component will also reset.

Why is my react function returning [object,object]

I have a function in my Numbers component that should return the state however it returns [object,object] I cant see what i've done wrong?
I've written a function in Numbers, that returns another function in my apps component!
import React, { Component } from 'react';
import Numbers from './Numbers'
import './App.css';
class App extends Component {
constructor(props){
super()
this.state={
calcValue:0
}
}
takeValue = (n) => {
alert(n)
}
render() {
return (
<div className="App">
<Numbers submit={(n) => this.takeValue(n)} numberValue={1}/>
</div>
);
}
}
export default App;
Number component:
import React, { Component } from 'react';
import propTypes from 'prop-types';
class Numbers extends Component {
constructor(props){
super();
this.state={
numberValue:6
}
}
submit = (n) => {
this.props.takeValue(this.state.numberValue)
}
render() {
return (
<div>
<button value={this.state.numberValue} onClick={this.props.submit}>
{this.props.numberValue}
</button>
</div>
)
}
}
// Completed.propTypes={
// test:propTypes.string.isRequired
export default Numbers
You are not understanding concept of passing the props. you need to differentiate what you are passing into child component and how you want to call the parent from child.
Change
onClick={this.props.submit}
to
onClick={this.submit}
and
submit=(n) => {
this.props.takeValue(this.state.numberValue)
}
to
submit = (n) => {
this.props.submit(this.state.numberValue)
}
onClick={this.props.submit} will call parent component not the child one
Demo
Thanks I have found my error! Should be this.submit not this.props.submit
Also I needed to call the takeValue function
Thanks

How to include the Match object into a ReactJs component class?

I am trying to use my url as a parameter by passing the Match object into my react component class. However it is not working! What am I doing wrong here?
When I create my component as a JavaScript function it all works fine, but when I try to create my component as a JavaScript class it doesn't work.
Perhaps I am doing something wrong? How do I pass the Match object in to my class component and then use that to set my component's state?
My code:
import React, { Component } from 'react';
import axios from 'axios';
import PropTypes from 'prop-types';
class InstructorProfile extends Component {
constructor(props, {match}) {
super(props, {match});
this.state = {
instructors: [],
instructorID : match.params.instructorID
};
}
componentDidMount(){
axios.get(`/instructors`)
.then(response => {
this.setState({
instructors: response.data
});
})
.catch(error => {
console.log('Error fetching and parsing data', error);
});
}
render(){
return (
<div className="instructor-grid">
<div className="instructor-wrapper">
hi
</div>
</div>
);
}
}
export default InstructorProfile;
React-Router's Route component passes the match object to the component it wraps by default, via props. Try replacing your constructor method with the following:
constructor(props) {
super(props);
this.state = {
instructors: [],
instructorID : props.match.params.instructorID
};
}
Hope this helps.
Your constructor only receives the props object, you have to put match in it...
constructor(props) {
super(props);
let match = props.match;//← here
this.state = {
instructors: [],
instructorID : match.params.instructorID
};
}
you then have to pass that match object via props int a parent component :
// in parent component...
render(){
let match = ...;//however you get your match object upper in the hierarchy
return <InstructorProfile match={match} /*and any other thing you need to pass it*/ />;
}
for me this was not wrapping the component:
export default (withRouter(InstructorProfile))
you need to import withRouter:
import { withRouter } from 'react-router';
and then you can access match params via props:
someFunc = () => {
const { match, someOtherFunc } = this.props;
const { params } = match;
someOtherFunc(params.paramName1, params.paramName2);
};
Using match inside a component class
As stated in the react router documentation. Use this.props.match in a component class. Use ({match}) in a regular function.
Use Case:
import React, {Component} from 'react';
import {Link, Route} from 'react-router-dom';
import DogsComponent from "./DogsComponent";
export default class Pets extends Component{
render(){
return (
<div>
<Link to={this.props.match.url+"/dogs"}>Dogs</Link>
<Route path={this.props.match.path+"/dogs"} component={DogsComponent} />
</div>
)
}
}
or using render
<Route path={this.props.match.path+"/dogs"} render={()=>{
<p>You just clicked dog</p>
}} />
It just worked for me after days of research. Hope this helps.
In a functional component match gets passed in as part of props like so:
export default function MyFunc(props) {
//some code for your component here...
}
In a class component it's already passed in; you just need to refer to it like this:
`export default class YourClass extends Component {
render() {
const {match} = this.props;
console.log(match);
///other component code
}
}`

React - passing object through props

I am new to React and trying to pass object through attributes but getting following error.
Uncaught Invariant Violation: Objects are not valid as a React child (found: object with keys {title}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of MeetingComponent.
Here is my code:
Main.jsx
import React from 'react';
import MeetingComponent from '../components/Meeting.jsx';
let meeting = {
title: 'Some title'
};
class AppComponent extends React.Component {
render() {
return (
<div className="index">
<MeetingComponent dataMeeting={meeting} />
</div>
);
}
}
AppComponent.defaultProps = {};
export default AppComponent;
Meeting.jsx
import React from 'react';
class MeetingComponent extends React.Component {
render() {
return (
<div>{this.props.dataMeeting}</div>
);
}
}
MeetingComponent.defaultProps = {};
export default MeetingComponent;
How can I solve this? What is the best practice?
The problem is here
<div>{this.props.dataMeeting}</div>
You cannot render an object in React, maybe you were trying to do
<div>{this.props.dataMeeting.title}</div>
If you want to pass properties of an object , it can be done as follows:
<MeetingComponent {...meeting} />
To access title of the meeting object inside the Meeting component, you can do it by calling it directly this.props.title
You can render it as <div>{this.props.title}</div>
i've used this method to pass object through component
let meeting = {
title: 'Some title'
};
class AppComponent extends React.Component {
render() {
const jsonData =JSON.stringify(meeting);
return (
<div className="index">
<MeetingComponent dataMeeting={jsonData } />
</div>
);
}
}
class MeetingComponent extends React.Component {
render() {
const data = JSON.parse(this.props.dataMeeting);
return (
<div>{data}</div>
<div>{data.title}</div>
);
}
}
static propTypes = {
pieChartSortSettings: PropTypes.shape({
type: PropTypes.string.isRequired,
order: PropTypes.string.isRequired,
}),
};
Here is a example how to pass object in props. You can also checkout methods like: PropTypes.arrayOfand PropTypes.objectOf(more: https://reactjs.org/docs/typechecking-with-proptypes.html)
Best practice is make your props as plain as possible, in your case it may be
<MeetingComponent title={ meeting.title } />
class MeetingComponent extends React.Component {
propTypes = {
title: React.PropTypes.string.isRequired
}
render() {
return (
<div>title: { this.props.title }</div>
);
}
}
And always use propTypes for better warning messages

Resources