React. how to pass props from onClick to function - reactjs

I am new to React, I am trying to create an app in which I can click on a button and a function will run countdown timer, but If I pass props from onClick to begin function like this, onClick={begin(props.subject)} the function will run before I click. and if I use onClick with begin without argument, there is no props being passed down. how can I fix that? thanks
import React from 'react';
import SubjectForm from './SubjectForm';
const EditSubject=(props)=>{
return(
<div>
<button onClick={begin}>start</button>
</div>)
};
const begin = (props)=> {
console.log(props.subject)
}
const mapStateToProps=()=>{};
export default connect(mapStateToProps)(EditSubject);
also, is there a way or trick to use a variable inside of begin function from an outside function? so I can make a pause button to pause seInterval in begin function.

You are using functional (stateless) components in this example. You can also use ES6 classes to represent React components, with functions being methods of the class. Then you may make functions like begin in your code as class methods, so they can access class data members like props.
See the code below:
import React from 'react';
import SubjectForm from './SubjectForm';
class EditSubject extends React.Component {
constructor() {
super();
this.begin = this.begin.bind(this);
}
begin() {
console.log(this.props.subject);
}
render() {
return (
<div>
<button onClick={begin}>start</button>
</div>
);
}
};
const mapStateToProps=()=>{};
export default connect(mapStateToProps)(EditSubject);
This is just a best practice if your component has states, and methods. Using functional components like in your example, you may use simply the following:
const EditSubject = (props) => {
return (
<div>
<button
onClick={() => begin(props)} // using props here
>
start
</button>
</div>
);
};
Simple, right ?

Related

React - What is meant by 'Do not use HOC’s in the render method of a component. Access the HOC outside the component definition.'?

I am learning HOCs and keep reading the above quote, but I do not understand what it means. If my HOC adds a method to my consuming component, can I use that method in the render method like so? If not how would I do what I am trying to do here:
import React, { Component } from 'react';
import { withMyHOC } from '../with_my_component'
class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
const { methodFromHOC }= this.props;
const result = methodFromHOC(someArgument);
return (
<div >
{result}
</div>
)
}
}
export default withMyHOC(MyComponent );
When you say, do not use HOC within the render method, it means that you shouldn't create an instance of the component wrapped by HOC within the render method of another component. For example, if you have a App Component which uses MyComponent, it shouldn't be like below
import React, { Component } from 'react';
class MyComponent extends Component {
constructor(props) {
super(props);
}
render() {
const { methodFromHOC }= this.props;
const result = methodFromHOC(someArgument);
return (
<div >
{result}
</div>
)
}
}
export default MyComponent;
import { withMyHOC } from '../with_my_component'
export default class App extends React.Component {
render() {
const Wrap = withMyHOC(MyComponent);
return (
<div>
{/* Other Code */}
<Wrap />
</div>
)
}
}
Why you shouldn't use it like above is because everytime render method is called a new instance of the MyComponent is created wrapped by HOC called Wrap and hence everytime it be be mounted again instead of going by the natural lifecycle or React.
However if your HOC passes a function as props, you can use it within the render as long as it doens't cause a re-render again otherwise it will lead to a infinite loop.
Also its better to memoize functions which are called in render directly to avoid computation again and again
CodeSandbox Demo
A High Order Component is a function which returns a Component, not jsx. When wrapping a component with an hoc, you're not changing the returned value of your component, you're changing the signature itself. Consider the following hoc
const withFoo = Component => props =>{
return <Component {...props} foo='foo' />
}
withFoo is a function which takes a Component (not jsx) as argument and returns a component. You don't need to call an hoc from render because the values it injects are already inside props of the wrapped component.
An hoc tells how a wrapped component will look like, changes it's definition so the only place to use it is in the component definition itself. Calling an hoc inside render creates a new instance of that component on each render. It's the equivalent of
const Component = () =>{
const ChildComponent = () =>{
return <span> Child </span>
}
return <ChildComponent /> //You're declaring again on each render
}
Use your high order components like this
const Component = ({ foo }) => <div>{ foo }</div>
export default withFoo(Component)
Or
const Component = withFoo(({ foo }) => <div>{ foo }</div>)

Define Functions for OnClick in React Component with ES6 Syntax

I currently structure my React Components the following:
export default class Heading extends Component {
render() {
return (
<h1 onClick={changeLanguage("en_US")}>I am a Heading!</h1>
);
}
}
And now after some research I haven't found any way to define functions inside the Component Class that can be used inside the onClick attribute of something.
Everything I found was only for React.createClass or something like that.
You should be able to define the method inside of your component. You will need to wrap your event handler so you can pass an argument to it
export default class Heading extends Component {
changeLanguage(lang){
}
render() {
return (
<h1 onClick={()=>this.changeLanguage("en_US")}>I am a Heading!</h1>
)}
If the function is outside the render, you would refer to it like so:
export default class Heading extends Component {
changeLanguage = () => {
//do something
}
render() {
return (
<h1 onClick={()=>this.changeLanguage("en_US")}>I am a Heading!</h1>
);
}
}
changeLangue needs to be an arrow function to maintain context.

React.js - how to pass event handlers to deeply nested component without props drilling?

I have the structure of components (nested) that seems like this:
Container
ComponentA
ComponentB
ComponentC(want to handle event here with state that lives on container)
Do I need to pass as props all the way from Container, ComponentA, ComponentB and finally ComponentC to have this handler? Or is there another way like using Context API?
I'm finding a bit hard to handle events with react.js vs vue.js/angular.js because of this.
I would recommend using either Context API (as you mentioned) or Higher Order Components (HoC)
Context Api is your data center. You put all the data and click events that your application needs here and then with "Consumer" method you fetch them in any component regardless of how nested it is. Here is a basic example:
context.js //in your src folder.
import React, { Component, createContext } from "react";
import { storeProducts } from "./data"; //imported the data from data.js
const ProductContext = createContext(); //created context object
class ProductProvider extends Component {
state = {
products: storeProducts,
};
render() {
return (
<ProductContext.Provider
//we pass the data via value prop. anything here is accessible
value={{
...this.state,
addToCart: this.addToCart //I wont use this in the example because it would
be very long code, I wanna show you that, we pass data and event handlers here!
}}
>
// allows all the components access the data provided here
{this.props.children},
</ProductContext.Provider>
);
}
}
const ProductConsumer = ProductContext.Consumer;
export { ProductProvider, ProductConsumer };
Now we set up our data center with .Consumer and .Provider methods so we can access
here via "ProductConsumer" in our components. Let's say you want to display all your products in your home page.
ProductList.js
import React, { Component } from "react";
import Product from "./Product";
import { ProductConsumer } from "../context";
class ProductList extends Component {
render() {
return (
<React.Fragment>
<div className="container">
<div className="row">
<ProductConsumer>
//we fetch data here, pass the value as an argument of the function
{value => {
return value.products.map(product => {
return <Product key={product.id} />;
});
}}
</ProductConsumer>
</div>
</div>
</React.Fragment>
);
}
}
export default ProductList;
This is the logic behind the Context Api. It sounds scary but if you know the logic it is very simple. Instead of creating your data and events handlers inside of each component and prop drilling which is a big headache, just put data and your event handlers here and orchestrate them.
I hope it helps.

React component without extend React Component class

I see in some source code, the author wrote a component like this:
import React from 'react';
export const Login = () => (
<div>
<h4>Hello World</h4>
</div>
);
export default Login;
The thing I don't know is:
How react understand this is a react component by only using import
How can I add another callback method, such as viewDidMount ... I have added in code block but it compiles fail.
thanks
This is functional stateless component. It is for simple components.
You also can add component property types like this:
export const Login = () => (
<div>
<h4>Hello World</h4>
</div>
);
Login.propTypes = {
username: React.PropTypes.string.isRequired,
}
You can add callback like this:
// this place to define callback is more effective
const onClick = e => (...)
const Login = props => {
// or define here if you need access to props in onClick
const onClick = e => (...)
return <button onClick={onClick}>Submit</button>
}
React "knows" that the code you wrote is a React Component because of transpilation. Transpilation is a process that occurs during build time where your code is changed from the code you wrote into something else.
In the case of React and JSX, your code turns into
export const Login = () => (
React.createElement('div', {},
React.createElement('h4', {}, 'Hello World')
);
);
The angle brackets (<) are syntactic sugar for React.createElement and people use the angle brackets because they are simpler to use and type.

React/ES6 -> How to call an React component class method from another component?

Is it possible to call class methods from other (React) components from within a class/component?
Example:
// file x.js
import React, { Component } from 'react'
class X extends Component {
methodY() {
console.log('methodY')
}
render() {
return <div />
}
}
export default X
// file z.js
import React, { Component } from 'react'
class Z extends Component {
render() {
return <button onClick={X.methodY} />
}
}
export default Z
It might be possible from a technical point of view - but you really shouldn't.
It's important when starting to use a new framework to embrace the ideology and the patterns of its community. In the case of React, there's no such things as classes and methods. Instead, there's only components and data (and to some extend state).
Following flux principle, you should try to architecture your application in a way that data flows a single way. From the top to the bottom.
As such, instead of component Z calling a function on component X, you can have X receive a function from the parent component modifying the state of that component and then passing a new value to X.
const A = ({onClick}) => (
<button onClick={onClick}>Click me</button>
);
const B = ({value}) => (
<span>{value}</span>
);
class Parent extends React.Component {
constructor() {
this.state = {
foo: 'foo'
};
}
render() {
return (
<div>
<A onClick={() => this.setState({foo: 'bar'})}/>
<B value={this.state.foo}/>
</div>
);
}
}
As you can see, the parent component is now in charge of handling the state and connecting different sibling components together.
As you move further into your exploration of React, you might start to use Redux to extract the logic around data and state completely outside your component. What you'll end up with is presentational components and containers components.

Resources