Function passed through props shown non-defined - javascript

I have got three components Topicscreen, Listview, Listrow. I am passing the function renderrow, and two other properties defined in my
Topicscreen to Listview.
Now when i call func in Listview, the props are passed to Listrow as defined in renderrow function, but the onRowclick function which is being passed to Listrow is undefined when i checked it in Listrow.
How to solve this error and pass onRowclick as a function to Listrow?
Topicscreen.js
class Topicscreen extends Component {
constructor() {
super();
this.onRowClick = this.onRowClick.bind(this);
}
componentDidMount() {
this.props.dispatch(topicaction.Fetchtopics());
}
renderLoading() {
return <p>Loading...</p>;
}
renderrow(rowid, topic) {
//const selected = this.props.checkselection[rowid]
const selected = "";
return (
<Listrow selected={selected} clicking={this.onRowClick} rowid={rowid}>
<h3>{topic.title}</h3>
<p>{topic.description}</p>
</Listrow>
);
}
onRowClick(rowid) {
this.props.dispatch(topicaction.selectedchoice(rowid));
}
render() {
if (!this.props.topicsByurl) return this.renderLoading();
return (
<div className="TopicsScreen">
Hi I am topic screen
<h1>Choose any three of the below topics</h1>
<Listview
rowid={this.props.topicsurlArray}
row={this.props.topicsByurl}
func={this.renderrow}
/>
</div>
);
}
}
Listview.js
import React, { Component } from "react";
import _ from "lodash";
export default class Listview extends Component {
constructor() {
super();
this.show = this.show.bind(this);
}
show(rowid) {
return this.props.func(rowid, _.get(this.props.row, rowid));
}
render() {
console.log("props in listview", this.props);
return (
<div>
<ul>{_.map(this.props.rowid, this.show)}</ul>
</div>
);
}
}
Listrow.js
import React, { Component } from "react";
export default class Listrow extends Component {
clicking() {
this.props.clicking(this.props.rowid);
}
render() {
console.log("list row called");
console.log("listrow props", this.props);
const background = this.props.selected ? "#c0f0ff" : "#fff";
return (
<div style={{ background }} onClick={this.clicking.bind(this)}>
{this.props.children}
</div>
);
}
}

You also need to bind your renderrow method in the Topicscreen constructor, or this.onRowClick inside of renderrow will not be what you expect.
class Topicscreen extends Component {
constructor(props) {
super(props);
this.onRowClick = this.onRowClick.bind(this);
this.renderrow = this.renderrow.bind(this);
}
// ...
}

Related

Calling parent function after setInterval timeout

In my react app I am using a timer component. I want this component to run in the background and call a parent function after a certain time. The code is giving error. My code is
parent component
import React, { Component } from 'react';
import Timer from './timer';
class Parent extends Component {
finish(){
console.log('fininsh')
}
render() {
return (
<div>
<Timer data={this.finish.bind(this)} />
</div>
);
}
}
export default Parent;
timer component
import React, { Component } from 'react';
class Timer extends Component {
constructor(props){
super(props);
this.state = {
fin: false
}
}
componentDidMount(){
this.myInterval = setInterval(() => {
this.setState({fin: true})
}, 10000);
}
childfinish = () => {
this.props.data.finish
}
render() {
const {fin} = this.state;
if(fin){
return(
<div>
{this.childfinish};
</div>
)
} else {
return (
<div>
<h1>Counting...</h1>
</div>
)
}
}
}
export default Timer;
the error is
Expected an assignment or function call and instead saw an expression
data prop does not contain function finish().
Remove {this.childfinish} from render() and
componentDidMount(){
this.myInterval = setInterval(() => {
this.setState({fin: true})
this.props.data();
}, 10000);
}
Found the solution
parent component
import React, { Component } from 'react';
import Timer from './timer';
class Parent extends Component {
finish(){
console.log('fininsh')
}
render() {
return (
<div>
<Timer data={{callfinish : this.finish.bind(this)}} />
</div>
);
}
}
export default Parent;
Child Component
import React, { Component } from 'react';
class Timer extends Component {
constructor(props){
super(props);
this.state = {
fin: false
}
}
componentDidMount(){
this.myInterval = setInterval(() => {
this.setState({fin: true})
}, 10000);
}
childfinish = () => {
clearInterval(this.myInterval);
this.props.data.callfinish();
}
render() {
const {fin} = this.state;
if(fin){
this.childfinish();
return (
<div></div>
)
} else {
return (
<div>
<h1>Counting...</h1>
</div>
)
}
}
}
export default Timer;
The parent function will run after 10 seconds.

TypeError: Cannot read property 'handleClick' of undefined React JS

I am new to React and I can't seem to figure this out. I am trying an exercise online and when I try passing an event on my child component I get an error "cannot read property 'handleClick' of undefined" error. Here is my code.
import React from "react";
import TodoItems from "./TodoItems";
import TodoComponent from "./TodoComponent";
class App extends React.Component {
constructor() {
super();
this.state = {
todoanItem: TodoItems
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(id) {
this.setState(function(state) {
const newstate = state.todoanItem.map(function(todo) {
if (todo.id === id) {
todo.complete = !todo.complete;
}
return todo;
});
return {
todoanItem: newstate
};
});
}
render() {
const theItems = this.state.todoanItem.map(function(item) {
return (
<TodoComponent
key={item.id}
item={item}
handleClick={this.handleClick}
/>
);
});
return <div>{theItems}</div>;
}
}
export default App;
import React from "react";
class TodoComponent extends React.Component {
render() {
return (
<div className="todo-items">
<input
type="checkbox"
checked={this.props.item.completed}
onChange={event => this.props.handleClick(this.props.item.id)}
/>
<p>{this.props.item.todo}</p>
</div>
);
}
}
export default TodoComponent;
You need to use an arrow function in the render function of App:
const theItems = this.state.todoanItem.map((item) => { // Here
return (
<TodoComponent
key={item.id}
item={item}
handleClick={this.handleClick}
/>
);
});
Also, add a constructor in the TodoComponent:
constructor(props) {
super(props);
}

Not rendering component onClick

The component I am trying to render:
import React, { Component } from 'react';
export default class QueryPrint extends Component {
render() {
console.log('working');
return (
<div>Hello</div>
)
}
}
The component that is trying to call it:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import {
Button,
} from 'reactstrap';
import QueryPrint from './bq_print';
class QueryResults extends Component {
constructor(props) {
super(props);
this.print = this.print.bind(this);
}
print() {
console.log('Clicked');
return (
<QueryPrint />
);
}
render() {
return (
<Button
className='cuts-btn'
color='success'
onClick={this.print}
>
Print
</Button>
)
}
}
function mapStateToProps(state) {
return {
query_data: state.results.query_data
}
}
export default connect (mapStateToProps, null)(QueryResults);
The console.log('clicked') is working, but the component that is supposed to render in that method doesn't--no console.log('working') or <div>.
Returning something from a click callback has no effect. If you want to render something, you do so in the render method. The click callback's job is to call this.setState(), which will then kick off a render.
Perhaps something like this:
class QueryResults extends Component {
constructor(props) {
super(props);
this.print = this.print.bind(this);
this.state = {
queryPrint: false,
}
}
print() {
console.log('Clicked');
this.setState({ queryPrint: true })
}
render() {
const { queryPrint } = this.state;
return (
<React.Fragment>
{queryPrint && <QueryPrint />}
<Button
className='cuts-btn'
color='success'
onClick={this.print}
>
Print
</Button>
</React.Fragment>
)
}
}
React Native works differently. It is more like a web app - you need to navigate to the other component.
Look at this example its very to the point: https://facebook.github.io/react-native/docs/navigation
Alternatively if you want to make only part of the screen change you will need to include it into your own render and control it thru a flag or a state machine.
https://facebook.github.io/react-native/docs/direct-manipulation

Exposing a method on a React Component

This is my code
import React, { Component } from "react";
import { render } from "react-dom";
class CView extends Component {
someFunc() {
alert(1);
}
render() {
return <div>Hello, there</div>;
}
}
class App extends Component {
getControl() {
this.cv = <CView />;
return this.cv;
}
render() {
return (
<div>
<h2 onClick={() => this.cv.someFunc()}>Click Me</h2>
{this.getControl()}
</div>
);
}
}
render(<App />, document.getElementById("root"));
Also available on https://codesandbox.io/s/k2174z4jno
When I click on the h2 tag, I get an error saying someFunc is not defined. How can I expose a function of a component so that other components can access it?
Thanks
I think that this.cv = <CView />; will not directly return instance of CView component.
onClick={() => {
console.log(this.cv instanceof CView); // false
this.cv.someFunc();
}}
But if you try to use refs you will access it.
class App extends Component {
constructor(props) {
super(props)
this.cv = React.createRef();
}
onClick() {
this.cv.current.someFunc();
}
render() {
return (
<div>
<h2 onClick={() => this.onClick()}>Click Me</h2>
<CView ref={this.cv} />
</div>
);
}
}
It is more "React way" though. https://codesandbox.io/s/vy61q9o8xy

Cannot figure out why data won't load into React component

Here is my store:
import helper from './../../helpers/RestHelpers.js';
var posts = [];
class PostStore {
constructor() {
helper.get('/api/posts')
.then((data) => {
posts = data;
console.log(posts);
}
);
}
getPosts() {
return posts;
}
};
export default new PostStore();
When I console.log posts from within the helper function, I get the correct data. But when I console.log from the component, the array of posts is empty.
Here is my component:
import React from 'react';
import postStore from '../stores/PostStore';
class Home extends React.Component {
constructor() {
super();
this.state = {
posts: postStore.getPosts()
}
console.log(this.state.posts);
}
render() {
return (
<div className="welcome">
{this.state.posts.map(function(post, index) {
return (
<PostItem post={post} key={"post " + index} />
)
})
}
</div>
)
}
}
class PostItem extends React.Component {
render() {
return <div>{this.props.post.postName}</div>;
}
}
export default Home;
I wouldn't use your PostStore as-is. Instead just use your helper directly like so:
import React from 'react';
// import your helper!
class Home extends React.Component {
componentDidMount() {
helper.get('/api/posts').then((data) => {
this.setState({posts: data})
});
}
render() {
return (
<div className="welcome">
{this.state.posts.map((post, idx) => <PostItem post={post} key={"post " + idx} />)}
</div>
)
}
}

Categories

Resources