Convert ng-click code to react component - javascript

I have this following button with ng-click
<button ng-click="productClass.saveProductMehod()">Save</button>
and i try to convert it to React
<button-component on-submit="productClass.saveProductMehod"
value="'Save'"></button-component>
with
class ButtonComponent extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onSubmit();
}
render() {
return (
<button onClick={this.handleClick}>
{this.props.value}
</button>
);
}
}
ButtonComponent.propTypes = {
value: PropTypes.string.isRequired,
onSubmit: PropTypes.func.isRequired,
};
export { ButtonComponent }
ProductClass
class ProductClass {
saveProductMehod() {
this.submitted = true;
//save the product
}
}
The problem here is when the i click the button i loose this initialization from constructor of the ProductClass and when it gets in the saveProductMethod the this is the props object. What am i missing?

There are a few pieces missing here:
<button-component on-submit="productClass.saveProductMehod"
value="'Save'"></button-component>
Should be (noting the quotes around save and the quotes onSubmit, as well as the case):
<ButtonComponent onSubmit={productClass.saveProductMehod}
value="Save"></ButtonComponent>

Let us assume your angular ng-click to be:
<button ng-click="onClick()">Save</button>
Analogous React Component (Stateless Form) would be:
const ReactButton = props =>(<button onClick={props.onClick} value={props.value}/>)
Analogous React Component (Class Based Form) would be:
class ReactButton extends React.Component{
render(){
return(<button
onClick={this.props.onClick}
value={this.props.value}/>)
}
}
Usage of this ReactButton:
Thats it!
Important Points to keep in mind:
Custom Component follow convention that they start with Capital
Alphabet and follow camel case syntax.
JSX is just like html. Only class -> className.
Every Component Name should be a valid JS variable

The new method must be binded to the controller in order to have access to predefined attributes:
this.saveProductMehod = this.saveProductMehod.bind(this);

Related

React pass function to dynamic created child with additional parameter

I want to dynamically create child components, receiving an onClick event from their parent/grandparent component in React. During the creation I want to add a parameter to the onClick-event. Basically the desired flow is:
When rendering parent component
Pass the reference to the desired function to the creation of the dynamic component
In process of creating the dynamic component I want to add a parameter, defined by the creator
the onClick event in the child should call the onClick function in the parent using the parameter it got from the creator of the dynamic component
For the code: this is the dynamic component creator and the parent
import React from 'react';
// This is the creator of my dynamic components
// It currently sets this.props.name as parameter for the parent function
class CreateComponent extends React.Component {
render(){
return(
<div className="childBox">
// this.props.component is a react component of type ImageBox (see next code block)
{React.cloneElement(this.props.component, {
open: this.props.open(this.props.name),
close: this.props.close,
})}
</div>
)
}
}
// This is the parent component, using the creator and some state to open/close different components
export class DynamicContentGrid extends React.Component {
constructor() {
super();
this.state = { activeComponent: '' };
}
close() {
this.setState({ activeComponent: '' });
}
open(component) {
this.setState({ activeComponent: component })
}
render() {
console.log(this.props.children);
return(
<div className={css(styles.grid)}>
<div className={css(styles.boxUpperLeft, styles.box)}>
<CreateComponent
component={this.props.children['upperLeft']}
name='upperLeft'
open={() => (name) => this.open(name)}
close={() => this.close()}
/>
</div>
</div>
)
}
}
export default DynamicContentGrid;
And here comes the very basic child component using this.props.close without parameters (they should be set in the creator):
import React from 'react';
export class ImageBox extends React.Component {
render() {
const {title, link, img} = this.props.content.front;
return(
<div>
<h1>{title}</h1>
<h2 onClick={this.props.open}>{link}</h2>
<img src={img} />
</div>
)
}
}
export default ImageBox;
What works
The dynamic rendering of child components works fine.
Where it breaks
As you can see, the magic happens in open={() => (name) => this.open(name)}. What I want is: pass this.open to the creator, set open(name) as parameter and pass on the open function to the child.
Everything works fine, if I said the "name" parameter directly in the parent, but for several reasons I do not want to do this. So I need some kind of currying but I can't figure out, what is wrong. The parameter "name" is not properly set in the creator at the moment.
In CreateComponent set open: () => this.props.open(this.props.name).
Also, remove () => (name) => this.open(name) and replace with this.open and put this.open = this.open.bind(this); into the constructor.

React/ ESLint - JSX props should not use arrow functions

I'm currently creating a component in react and i'm using the ES Lint rule react/jsx-no-bind. My issue here is that I want to be able to pass a parameter to my components function. Here is the code I would like to use to be able to do so:
class LanguageDropdown extends Component {
constructor(props) {
super(props);
this.state = {};
}
changeLanguage = (lang) => {
console.log(lang)
};
render() {
return (
<div>
{this.props.languages.map(lang => <button onCLick={() => this.changeLanguage(lang)}>{lang}</button>)}
</div>
)
}
...
This pulls up the ESlint error:
JSX props should not use arrow functions
I'm not entirely sure how to achieve this without using an arrow function or using .bind(). I could add a data-attribute to the button element and then just pass in the event into the changeLanguage function and fetch the attribute using event.target() but this doesn't feel like it's the way it should be approached in React.
Can someone tell me what would be the correct way?
You can refactor button into its own component:
class MyButton extends Component {
static propTypes = {
language: PropTypes.string.isRequired,
};
onClick = () => console.log(this.props.language);
render() {
const {language} = this.props;
return (
<button onClick={this.onClick} type="submit">
{language}
</button>);
}
}
and then in your LanguageDropDown class, use MyButton like this:
class LanguageDropdown extends Component {
...
render() {
return (
<div>
{this.props.languages.map(lang => <MyButton key={lang} language={lang}/>)}
</div>
)
}
...
}
A couple of additional things:
You have a typo onCLick should be onClick
You need a key for repeated items
try the below code.
here I tried by taking the value into the state, same can be tried using props.
class LanguageDropdown extends Component {
constructor(props) {
super(props);
this.state = {languages:['telugu','hindi','english']};
// this.changeLanguage = this.changeLanguage.bind(this);
}
changeLanguage(event,lang){
//event.preventDefault();
console.log('change lang: '+JSON.stringify(lang));
};
render() {
return (
<div>
{this.state.languages.map(lang => <button onClick={(event)=>this.changeLanguage(event,lang)}>{lang}</button>)}
</div>
)
}
}
render(<LanguageDropdown />, document.getElementById('root'));
when you bind the handler in the onClick event where you are passing the value to the handler, then we have to pass that value from the event and collect it to get that value.

Correct way to access value of an input initialized with a prop when button is clicked in react

I have a react component that consists of an input field and a button. When the button is clicked I want to run an update function that is also inherited from the parent controller. In the react documentation they have an onchange handler attached to this input and they get the new value of the input with the onchange event object. However in my case I get an event object describing the button, not the input field. What is the correct way to access the new input field value from handle click?
class QuoteButton extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick () {
this.props.onQuoteUpdate(//what should go here?)
}
render() {
const cost = this.props.cost;
return (
<div>
<Input value={cost}/>
<Button basic color='green' onClick={this.handleClick}>Submit Quote</Button>
</div>
);
}
}
If you a going to change input value in this component you need to use react states (if you don't use state management libraries such as mobx or redux). In most cases input have to be a controlled component.
After component was mounted add cost value to states. You also need appropriate handler for input.
P.S. You could use arrow functions to avoid binding handlers in constructor.
class QuoteButton extends React.Component {
constructor(props) {
super(props);
this.state = { inputValue: '' };
}
componentDidMount() {
this.setState({inputValue: this.props.cost});
}
handleClick = () => {
this.props.onQuoteUpdate(this.state.inputValue);
}
handleInputChange = event => {
this.setState({inputValue: event.target.value});
}
render() {
return (
<div>
<Input value={this.state.inputValue} onChange={this.handleInputChange} />
<Button basic color='green' onClick={this.handleClick}>Submit Quote</Button>
</div>
);
}
}
Hope it helps

React Executing a method inside a component

I have a component like this:
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props, context) {
super(props, context);
this.state = {
isActive: false,
}
}
showMyComponent() {
this.setState({
isActive: true,
});
}
hideMyComponent() {
this.setState({
isActive: false,
});
}
render() {
return (
<div>
<h1>Compoent Here</h1>
</div>
);
}
}
export default MyComponent;
Now, on my index.js I am adding several components.
...
<Header />
<Nave />
Can I now do something like this here:
MyComponent.showMyComponent();
Like you normally call a function?
If not, how is this done?
You can use references. In your render() method you can get the ref. e.g.
<MyComponent ref={ref => {this.myComponent = ref}}/>
You need to create a field myComponent and assign it to it. With that you can call it like this.myComponent.showMyComponent()
See here Refs and the DOM
Use State
You are thinking about react wrong. You should not have to call a components function like this ever.
You can pass a prop to the component that will make the component hide or show.
or wrap the component in a if in the parent. Use the parents state to hide or show the component.
Like
if (someCondition) {
<MyComponent />
}
It's doable, even if some people hates this option, cause it's not the official React way, true.
You can define any public method on your component classes (such as a reset method on a Typeahead) and call those public methods through refs (such as this.refs.myTypeahead.reset()). In most cases, it's clearer to use the built-in React data flow instead of using refs imperatively.
But However, thinking out of the box, is not forbidden so you can use refs for this.
class Parent extends Component {
onSomeThing() {
// Call some method of myChild
this.myChild.myChildsPublicMethod()
}
render() {
return <MyChild ref={ref => { this.myChild = ref; }} />
}
}
// MyChild
// Just as demo using Pure components here.
// You could use the normal class notation..
const MyChild = () => <div>Ola</div>;
MyChild.someMethod = () => console.log('Ola');
More here https://zhenyong.github.io/react/docs/more-about-refs.html

How to avoid using inline functions in React (ES6) for functions that take arguments

I'm trying to follow the suggestion in this react-eslint doc to avoid using inline functions.
I have a div with an onClick funciton like so:
onClick={ () => this.props.handleClick(some_constant) }
This works perfectly fine, however I don't want to have an inline function. When I try to abstract it by following the pattern in the provided link above, I get a setState error that runs infinitely.
class Foo extends React.Component {
constructor() {
super();
this._handleClickWrapper = this.handleClickWrapper.bind(this);
}
_handleClickWrapper() {
// handleClick is a callback passed down from the parent component
this.props.handleClick(some_constant)
}
render() {
return (
<div onClick={this._handleClickWrapper}>
Hello!
</div>
);
}
}
What needs to be done so that I can avoid using inline functions?
Edit:
I made a serious typo, but in my code, I have what is currently reflected and it is still causing the error.
You bound the wrong function to this. It should be:
this._handleClickWrapper = this._handleClickWrapper.bind(this);
This way _handleClickWrapper will always be bound to the context of the component.
If you really really really want to follow the jsx-no-bind rule, you can create a new component and pass someConstant in as a prop. Then the component can call your callback with the value of someConstant:
class FooDiv extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
render() {
return <div onClick={this.handleClick}>Hello!</div>
}
handleClick() {
this.props.onClick(this.props.someConstant);
}
}
Then your Foo component can just do this:
class Foo extends React.Component {
render() {
const someConstant = ...;
return (
<FooDiv
onClick={this.props.handleClick}
someConstant={someConstant}
/>
);
}
}
Having said that, I would recommend not following jsx-no-bind and just use bind or arrow functions in render. If you're worried about performance due to re-renderings caused by using inline functions, check out the reflective-bind library.
There is a typo
this._handleClickWrapper = this.handleClickWrapper.bind(this);
should be
this._handleClickWrapper = this._handleClickWrapper.bind(this);
in your constructor you forgot to pass props to super()
constructor(props) {
super(props);
this._handleClickWrapper = this._handleClickWrapper.bind(this);
}
Tipp: You can avoid binding (and even the constructor) by using arrow functions declaration inside the class (babel-preset-es2016).
class Foo extends React.Component {
state = {} // if you need it..
onClick = () => {
this.props.handleClick(some_constant)
}
render() {
return (
<div onClick={this.onClick}>
Hello!
</div>
);
}
}
This way you components gets smaller, and easier to read.
https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding

Categories