Passing a React click handler to child components - reactjs

My SquareClicker component renders a SquareGrid, which in turn contains clickable Squares:
class SquareClicker extends React.Component {
constructor(props) {
super(props);
this.state = {
grid: Array.from(Array(5).keys()).map(
i => Array.from(Array(5).keys()).map(
j => <Square key={((i*5)+j).toString()} onClick={this.handleClick}/>
)
)
}
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
console.log("A square has been clicked.");
}
render() {
return (
<div className="square-clicker">
<SquareGrid grid={this.state.grid}/>
</div>
);
};
}
class Square extends React.Component {
render() {
return (
<div className={"square"} />
);
};
}
When I click on squares, nothing is logged to the console.
This question is similar - but as you can see, I have bound the handleClick function to the component context with this.handleClick = this.handleClick.bind(this);.
How do I make my squares clickable?

I misread your post initially, sorry (I got <Square> and <SquareGrid> mixed up), try this in setting your <Square> component...
j => <Square key={((i*5)+j).toString()} click={this.handleClick}/>
Then in your <Square> component, set render() as so...
render() {
return (
<div
className={"square"}
onClick={(e) => this.props.click(e)}
/>
);
}

You have to pass click event to SquareGrid
// In SquareClicker
<SquareGrid grid={this.state.grid} click={this.handleClick} />
and inside SquareGrid component, you will use click prop like below:
class SquareGrid extends React.Component {
...
return (
// ...you code
<Square click={this.props.click} />
)
}
and then inside Square component pass this prop again
class Square extends React.Component {
render() {
return (
<div className={"square"} onClick={this.props.click}/>
);
};
}

Related

React access sub-components properties in main component

Would it be possible to access a sub-components properties in the main component in React?
For example I'm trying this: I've got a main component MyComponent and a SubComp sub-component that renders a button. Would it be possible to set the state of MyComponent equal to the tex property of the clicked SubComp?
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: 'Initial State'
};
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({name: SubComp.tex});
}
render() {
return (
<div>
<SubComp onClick={this.handleClick} tex="but1"/>
<SubComp onClick={this.handleClick} tex="but2"/>
<h1>{this.state.name}</h1>
</div>
);
}
};
class SubComp extends React.Component {
constructor(props){
super(props);
};
render(){
return(
<button onClick={this.props.onClick}>Click Me</button>
);
}
}
I've tried to do it in the handleClick method with SubComp.tex but it's obviously not working.
Thanks!
Pass the tex prop in SubComp via the callback:
render() {
return (
<button onClick={() => this.props.onClick(this.props.tex)}>Click Me</button>
);
}
And use it in the handleClick of MyComponent:
handleClick(tex) {
this.setState({name: tex});
}
Yes, this is definitely possible. Your idea of passing the function from the main component was right, but to achieve what you are trying to do, you could pass a parameter to the function, like this:
handleClick(e) {
this.setState({name: e.target.value});
}
Notice that I have added the e as a parameter to your handleClick function. This is the click event received from clicking the button. We then set the state equal to the value from this event.
You can also convert SubComp to functional component and pass it handleClick which you defined inside MyComponent as props:
const SubComp = ({handleClick}) => {
return <button onClick={handleClick}>Click me</button>
}
Then pass it handleClick method like so: <SubComp handleClick={this.handleClick} />

How to access method of the child component from parent in reactjs

I'm trying to call child component from parent component in reactjs using refs.but it throws error saying showModal() is not a function when I tried to call.
//app.js
class app extends Component {
constructor(props) {
super(props);
this.POPUP = React.createRef();
}
showModal(){
this.POPUP.showModal(true);
}
render() {
return (
<React.Fragment>
<span><a onClick={() => this.showModal()}>Show</a></span>
<POPUP onRef={ref => (this.POPUP = ref)}></POPUP>
</React.Fragment >
)
}
}
popup.js
class POPUP extends Component {
showModal(show) {
console.log('showmodal');
}
render() {
console.log(this.props.showModalPopup);
<React.Fragment>
<Modal
position="center">
<div>
//code
</div>
</Modal>
</React.Fragment>
)
}
}
Is there any alternative in nextjs.please help
https://reactjs.org/docs/refs-and-the-dom.html#accessing-refs
First of all if you want to access that POPUP instance you should do
this.POPUP.current.showModal(true);
BTW Your showModal function needs to be bound to the child component if you intend to alter its state.
However, even this is doable - this is usually not the recommended way of doing React.
If you want the parent to decide if showModalPopup should be true, you probably should keep the state inside of your parent component:
class App extends Component {
constructor(props) {
super(props);
this.state = { showModalPopup: false };
this.showModal = this.showModal.bind(this);
}
showModal(){
this.setState({ showModalPopup: true });
}
render() {
return (
<React.Fragment>
<span><a onClick={this.showModal}>Show</a></span>
<POPUP show={this.state.showModalPopup}></POPUP>
</React.Fragment >
)
}
}
const POPUP = ({ show }) => (
<Modal show={show} position="center">
// your content.
</Modal>
)

What is the right way to add onClick event on element after render?

I'd like to add onClick event only on an element of the list(array)
class App extends React.Component {
constructor(){
super();
this.state = {
list: ['Value1','Value2']
}
}
render(){
return (
<div className="App">
{this.state.list.map(data => {
return data
})} // How can I add onClick event only on 'Value1' after it rendered?
</div>
);
}
}
My solution is:
const [Value1,Value2] = this.state.list
value1.addEventListener('click',function(){})
but it seems like doesn't work.
In React, you can bind onClick in the component. You can read more about event handling in here: https://reactjs.org/docs/handling-events.html
Your code can be changed into this:
class App extends React.Component {
constructor() {
super()
this.state = {
list: ['Value1', 'Value2']
}
}
handleClick = e => {
console.log('You clicked the item!!')
}
render() {
return (
<div className="App">
{this.state.list.map(data => {
return (
<span onClick={data === 'Value1' ? this.handleClick : undefined}>
{data}
</span>
)
})}
</div>
)
}
}

Using childrens in React Container

Can I use children in React Container or is it wrong?
For example, I have a list of buttons(ActionButton) that are grouped together (ActionMenu).
import React from 'react';
class App extends React.Component {
render() {
return (
<ActionMenu>
<ActionButton name="New" icon="add" />
<ActionButton name="Delete" icon="remove" />
</ActionMenu>
)
}
}
class ActionMenu extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert('Click!');
}
render() {
return React.Children.map(this.props.children, (button) =>
React.cloneElement(button, {
onClick: this.handleClick
})
);
}
}
function ActionButton({ name, icon, onClick }) {
return <button class={icon} onClick={onClick}>{name}</button>
}
You can use children regardless of whether it's a component of container.
"[children are] especially common for components like Sidebar or Dialog that represent generic 'boxes'."
In your case you have a menu, which falls into this category.
https://reactjs.org/docs/composition-vs-inheritance.html
I think this is what you are after. Actually you should just put the children in its closest parent instead of its grandpa.
import React from 'react';
import { render } from 'react-dom';
function ActionButton({ name, handleClick }) {
return <button onClick={handleClick}>{name}</button>
}
class ActionMenu extends React.Component {
constructor(props) {
super(props);
}
handleClick = () => {
alert('Click!');
}
render() {
return (
<div>
<ActionButton name="add" handleClick={this.handleClick}/>
<ActionButton name="remove" handleClick={this.handleClick} />
</div>
);
}
}
class App extends React.Component {
render() {
return (
<ActionMenu />
)
}
}
render(<App />, document.getElementById('root'));
You can try to run it in sandbox.
By the way, using bind is quite redundant now, we can use public class fields syntax, which is already ECMA stage 2.

Trigger event when the state of child of another component changed in react

Let say I have two components called A and B.
B has a status which keeps changing and I would like to pass the status to A so that I can trigger event when certain condition is met.
How do I keep monitoring/getting state of child from another component in React?
Thanks!
When component on the same level:
class Parent extends React.Component {
constructor() {
super();
this.state = {
status: "B not clicked"
}
this.componentBchangeHandler = this.componentBchangeHandler.bind(this);
}
componentBchangeHandler(value) {
this.setState({ status: value })
}
render() {
return (
<div>
<ComponentA status={this.state.status} />
<ComponentB componentBchangeHandler={this.componentBchangeHandler} />
</div>
)
}
}
const ComponentA = (props) => <div>{props.status}</div>;
const ComponentB = (props) => <div onClick={() => props.componentBchangeHandler("some val")}>click me</div>;
https://codesandbox.io/s/k29mn21pov
And check out the documents I mentioned earlier.
If you're talking about a parent-child relationship, all you'd have to do is define a function that changes state on A and pass it as prop to B, like so:
class A extends Component {
constructor(props) {
super(props);
this.state = {
changed: false,
}
}
_statusChange = () => this.setState({ changed: !this.state.changed });
render() {
return(
<div>
<span>State on A: { this.state.changed.toString() }</span>
<B changeHandler={this._statusChange} />
</div>
)
}
}
class B extends Component {
render() {
return(
<div>
<button onClick={this.props.changeHandler}>Click me</button>
</div>
)
}
}
const App = () => (
<A />
);
If they should be on the same level, by convention, you should define a third component, wrap A and B in it, again passing state as props between them.

Resources