I am building a chess game using React and have a piece component which is draggable. When I handle drag events within the component itself I have no problems. However, when I try to pass drag events up to the parent component for handling, I get the error: TypeError: _this6.props.onDragStart is not a function.
The strangest part is that it seems to work until the error is thrown. I click the piece to move and and I get alerted with "starttt" which means that the function in the parent component was called successfully but then I get the error above implying that the function that was just called could not be found. I am very confused by this.
Here is my code for the parent component and draggable component.
class Square extends React.Component {
drag_start(event) {
alert('startttt')
}
renderSquare(color){
var class_name = "dark square"
var url = null;
if (this.props.value) {
url = this.props.value.url;
}
if (color) {
class_name = "light square"
}
if (url){
return <div className={class_name} onClick={() =>
this.props.onClick()} onDragStart = {(event) => this.drag_start(event)}
>
<ReactPiece url = {url}/> </div>
}
else {
return <div className={class_name} onClick={() =>
this.props.onClick()} > </div>
}
}
render() {
var color = this.props.color
return (
<React.Fragment>
{this.renderSquare(color)}
</React.Fragment>
);
}
}
class ReactPiece extends React.Component {
dragEnd = (event) => {
alert('end')
}
drop = (event) => {
alert('drop')
}
render() {
var url = this.props.url
return <img src={url} width="43" height="43" alt ='' draggable="true"
onDragStart={(event) => this.props.onDragStart(event)} onDrop=
{this.drop}
onDragOver={(event) => event.preventDefault()} onDragEnd={this.dragEnd} />;
}
}
You are not passing anything into the onDragStart props of ReactPeice
Related
I am new with refs in react.js and in the react-simplebar documentation it just shows how to get the scroll ref for a stateless function.
class App extends React.Component {
render() {
console.log(this.refs.scroll) // => Undefined
return (
<Simplebar ref={this.refs.scroll}><h1>scrollable element</h1></Simplebar>
)
}
}
For anyone coming to this at a later date. This is how I managed to set the scrolling position after a few hours of digging around in a function component
const SimpleScrollerComponent = () => {
// Create a reference for the SimpleBar component so we can acces it
const scrollableNodeRef = React.createRef();
const handleScrollDownBtnClicked = () => {
// This is where we set the scroll position
scrollableNodeRef.current.scrollTop = 1200;
};
return (
<div>
{/* We attach the reference to the component */}
<SimpleBar scrollableNodeProps={{ ref: scrollableNodeRef }}>
{/* This is where your code goes inside the scroll box */}
</SimpleBar>
<Button onClick={handleScrollDownBtnClicked}>Scroll to the Bottom</Button>
</div>
);
};
try this
class App extends React.Component {
constructor(props) {
super(props);
this.scrollableNodeRef = React.createRef();
}
onChangeScrollToTop() {
this.scrollableNodeRef.current.scrollTop = 0;
}
render() {
console.log(this.refs.scroll) // => Undefined
return (
<Simplebar scrollableNodeProps={{ ref:this.scrollableNodeRef }}>
<h1>scrollableelement</h1>
</Simplebar>
)
}
}
I am new to programming. I want to implement the below,
when I click a list item I want to navigate to another page.
What I am trying to do? I have list items in a side panel. when I click on the list item it should navigate to another page.
So I have a listpanel component which renders the listitem component. On click list item, based on item_data_type it should take to the link got from get_type1_link method. however, it returns an object. I am not sure where I am making mistake.
class ListPanel extends react.purecomponent {
get_type1_link = () => {
const item_data = this.props.item_data;
const itemss = this.props.items;
const {itemname, item_id} = item_data.properties;
const filtered_item = items && items.find(item => item.id ===
item_id);
const item_name = (filtered_item) ? filtered_item.itemname :
(itemname ? itemname : item_id);
if (filtered_item) {
return (<Link to={`/someurl/${item_data.properties.item_id}`}>
{item_name}</Link>);
} else {
return <span>{item_name}</span>;
}
};
get_link = () => {
const item_data = this.props.item_data;
let link;
switch (item_data.type) {
case 'type1':
link = this.get_type1_link();
break;
case 'type2':
link = this.get_type2_link(); //some method similar to
//get_type1_link method
break;
default:
return link=window.location.href;
}
return link;
};
render = () => {
const list_item = this.props.;
return (
<ListItem
key={list_item.id}
text={this.get_text}
link={this.get_link}/>
);
}
class ListItem extends react.purecomponent {
render = () => {
<li onClick={props.link}>
<div className="text">
{this.props.text}
</div>
</li>
}
}
I think there is a problem in the way I am storing the value returned from get_type1_link method into variable link. since get_type1_link returns a jsx (Link). Could someone help me with this thanks.
I think issue is with your extends,
class ListPanel extends react.purecomponent {
It should be
class ListPanel extends React.PureComponent {
And also another issue is your render function, you have not return anything. Your render function should return like,
class ListItem extends React.PureComponent {
render = () => {
return(
<li onClick={this.props.link}> //props.link should be this.props.link
<div className="text">
{this.props.text}
</div>
</li>
)
}
}
I'm trying to access the index of the selected tab in a React component so as to map it to props as follows:
class AttendanceDetail extends React.Component {
handleSelect(key, props) {
console.log(key)
props.index = key;
}
render(){
const {single_class, courses, attendances} = this.props;
// console.log(this.state);
if(single_class) {
return(
<div className='container content-section'>
// Some irrelevant Code
<Tabs defaultActiveKey={0} onSelect={this.handleSelect} id="uncontrolled-tab-example">
{ courses.map((course, index) => {
return (
<Tab eventKey={index} title={course.course + " year " + course.yearofstudy}>
//Other irrelevant code...
</Tab>
)
})}
</Tabs>
</div>
)
} else {
return (
<div className='container content-section'>
Loading Unit details...
</div>
);
}
}
}
So basically the handleSelect method is what determines the index of the selected tab and logs it to the console. The problem is, I'm tring to map that key (index) to props so as to access it else where but to no avail. Could someone help me out? What am I missing?
You're not supposed to set the component's props, only read. You can use state within the component:
export class Wrapper extends React.Component {
constructor() {
this.state = {
index: 0 //initial state
}
}
handleSelect(index, props) {
this.setState({index})
}
render() {
return (
<span>{this.state.index}</span>
)
}
}
you can read more on the official docs.
if i understood the scenario correctly, you need to log index value of the currently active tab. try using onFocus event handler to get the index value of the currently visible tab and set the state that will be used by handleSelect
constructor(props){
super(props);
this.state = {
index:''
}
}
the handler definition
setIndex = (index) => {
this.setState({index})
}
update handleSelect
handleSelect(index) {
console.log(index)
// call event handler of parent component eg: this.props.getIndex(index);
}
update tabs component handler
<Tabs defaultActiveKey={0} onSelect={() => {this.handleSelect(this.state.index)}} id="uncontrolled-tab-example">
call handler on focus of tab
<Tab
onFocus={() => {this.setIndex(index)}}
eventKey={index}
title={course.course + " year " + course.yearofstudy}>
//Other irrelevant code...
</Tab>
I passed a function from parent to child and implemented it onClick on the child. While clicking the button, I get the error:
this.props.function() is not a function.
/* PARENT */
class User extends React.Component {
buttonClicked(page)
{
this.setState({ page }, () => console.log(`NEW STATE`, this.state));
}
render()
{
return (
<Toolbar buttonClicked={page => this.buttonClicked(page)}/>
)
}
}
/* CHILD */
class Toolbar extends React.Component {
render()
{
let page = 3;
return (
<button value={page} onClick={page=> this.props.buttonClicked(e.target.value)}>
{page}
</button>
)
}
}
Error: bundle.js:34689 Uncaught TypeError: _this2.props.buttonClicked
is not a function at onClick (bundle.js:34689)
Declare your buttonClicked() with lexical binding through arrow function. Alternatively, you can bind the function in constructor.
And you access e.target.value from there:
buttonClicked = e => {
const page = e.target.value
// do your setState
}
You should pass down the function reference as props like this:
<Toolbar buttonClicked={buttonClicked}/>
In child component:
<button value={page} onClick={this.props.buttonClicked}>
{page}
</button>
Notice that we are merely passing down the reference of buttonClick() function, not calling. Only when the button is clicked, the function get called with event e, and we can then access e.target.value.
Read more about event handling in React here
You need to bind this value of the buttonClicked function to this of the parent. In your parent write this,
constructor(props) {
super()
this.buttonClicked = this.buttonClicked.bind(this)
}
The issue is not about the function but event e that is undefined when you use arrow function onClick={page => this.props.buttonClicked(e.target.value)}
class User extends React.Component {
buttonClicked(page) {
this.setState({ page }, () => console.log(`NEW STATE`, this.state));
}
render() {
return (
<Toolbar buttonClicked={page => this.buttonClicked(page)} />
)
}
}
/* CHILD */
class Toolbar extends React.Component {
render() {
let page = 3;
return (
<button value={page} onClick={e => this.props.buttonClicked(e.target.value)}>
{page}
</button>
)
}
}
render(<User />, document.getElementById('root'));
CodeSandbox
I'm a React newbie and ran into a problem with paging controls using link tags. My basic paging control renders as something like this:
Next
The JSX definition that renders it looks like this:
<a href={"#page"+(this.props.pageIndex+1)} onClick={this.handleClick}>
{this.props.name}
</a>
The problem is that when you click on the Next link to go to Page 2, the browser ends up showing #page3 in the URL bar, even though the code properly renders page 2. (The code does nothing to modify the URL.) Tracing following the JavaScript in the debugger, I see that window.location.href stays at #page1, then jumps to #page3.
I believe what is happening is that React is intercepting the click event, and re-renders the page properly, then the browser's default link handling fires after the Next link has changed to point to #page3 instead of #page2.
Is my analysis correct? If so, what is the proper way to make this work so the browser shows #page2 in the URL bar?
EDIT: Here is the simplified code in context:
class RecordList extends React.Component {
changePage(pageIndex) {
console.log("change page selected: "+pageIndex);
this.props.changePage(pageIndex);
return false;
}
render() {
...
nextLink = (<PagingLink name=" Next> "pageIndex={this.props.pageIndex+1} handleClick={() =>
this.changePage(this.props.pageIndex+1)}/>)
return (
...
<div className="paging-control">
<span>Page {this.props.pageIndex+1}</span>
{nextLink}
</div>
);
}
}
class PagingLink extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.handleClick(this.props.pageIndex)
}
render() {
return (
<span className="pageLink">
<a href={"#page"+(this.props.pageIndex+1)} onClick={this.handleClick}>
{this.props.name}
</a>
</span>
);
}
}
class App extends Component {
constructor() {
super();
this.state = {
pageSize: 20,
pageIndex: 0,
...
};
}
componentDidMount() {
var pageIndex = this.state.pageIndex;
if (window.location.hash.indexOf("#page") === 0) {
pageIndex = Number(window.location.hash.substring(5))-1;
this.setState((prevState) => {
return { pageIndex: pageIndex };
}, () => {
this.fetchRecords(pageIndex);
});
}
else {
this.fetchRecords(pageIndex);
}
}
fetchRecords(pageIndex) {
...
}
changePage(pageIndex) {
console.log("change page selected: "+pageIndex);
this.setState({pageIndex: pageIndex});
this.fetchRecords(pageIndex);
}
render() {
var content = (
<RecordList
records={this.state.records}
pageSize={this.state.pageSize}
pageIndex={this.state.pageIndex}
changePage={(pageIndex) => this.changePage(pageIndex)}
/>
)
return (
<div className="App">
...
{content}
</div>
);
}
prevent the default event on the anchor :
handleClick(event) {
event.preventDefault()
this.props.handleClick(this.props.pageIndex)
}
I could not get this working reliably with my own event handling and url rewriting, so I decided to simply rebuild it using React Router V4. When the going gets tough, it's always a good idea to not reinvent the wheel and let somebody else do the hard work for you.