React inline function in render with mobx - reactjs

Can I use bind function in render with mobx? I know that this practice leads to performance degradation, but my colleague says that if we use mobx we can do bind function in render
Example:
import { inject, observer } from 'mobx-react'
#inject('store')
#observer
export default class Component extends React.Component {
render() {
const {
store: {
pushByPath,
},
} = this.props
return (
<div>
<button
onClick={() => pushByPath('param1')}
/>
<button
onClick={() => pushByPath('param2')}
/>
<button
onClick={() => pushByPath('param3')}
/>
</div>
)
}
}

if you need your function pushByPath to be bound to an instance of a store, you may follow such pattern:
import {action} from 'mobx';
class Store {
#action.bound pushByPath(path) {
// this here will always point to an instance of Store
}
}
Actually, you can use bind and really recreating function is a performance hit, but really very minimal for modern browsers. And it does not matter do you use mobx or not.

Related

Ag-grid custom tooltip with functional component

I am looking at ag-Grid's example on creating a custom tooltip.
import React, {Component} from 'react';
export default class CustomTooltip extends Component {
getReactContainerClasses() {
return ['custom-tooltip'];
}
render() {
const data = this.props.api.getDisplayedRowAtIndex(this.props.rowIndex).data;
return (
<div className="custom-tooltip" style={{backgroundColor: this.props.color || 'white'}}>
<p><span>{data.athlete}</span></p>
<p><span>Country: </span> {data.country}</p>
<p><span>Total: </span> {data.total}</p>
</div>
);
}
}
According to ag-Grid's react component page, "If you wish to override the style of this div you can either provide an implementation of the ag-react-container class, or via the getReactContainerStyle or getReactContainerClasses callbacks on the React component:"
How would I go about creating a custom tooltip using a functional component? I am not sure how I would provide an implementation of the getReactContainerClasses callback.
You won't be able to have the public function getReactContainerClasses in a functional component, you'd need to write a class component. If you want to write a functional component, just set the CSS class directly on the container DOM element, similarly to their vanilla JS example. Below is a functional tooltip example which sets the class custom-tooltip.
import React, {Component} from 'react';
export const FunctionalCustomTooltip = (props) => {
props.reactContainer.classList.add('custom-tooltip');
const data = props.api.getDisplayedRowAtIndex(props.rowIndex).data;
return (
<div className="custom-tooltip" style={{backgroundColor: props.color || 'white'}}>
<p><span>{data.athlete}</span></p>
<p><span>Country: </span> {data.country}</p>
<p><span>Total: </span> {data.total}</p>
</div>
);
};
Fully working example:
https://plnkr.co/edit/WHEgtw0YVia1BVP4SVO8?p=preview
You can have public function using React Hooks with useImperativeHandle hook.
export const Component = forwardRef((props: ComponentParams, ref: any) => {
useImperativeHandle(ref, () => {
return {
getReactContainerClasses() {
return ['grid-container'];
},
};
});
}

How to click automatically in a button when user coming to page

import React from "react";
checkClick = () => {
console.log("clicked");
};
class Test extends React.Component {
render() {
return (
<div>
<button id="button" onClick={this.checkClick}>
click
</button>
</div>
);
}
}
export default Test;
How to click automatically on a button when user coming to page?
Here I want to click automatically above button.
I tried with:
document.getElementById("button").click()
which does not work.
You can use a ref which gives you an instance of the dom element, where you can call the click() method.
If you aren't familiar with refs, you can read all about them here: https://reactjs.org/docs/refs-and-the-dom.html
import React, { Component } from 'react'
class Test extends Component {
constructor(props) {
super(props)
this.button = React.createRef()
}
componentDidMount() {
this.button.current.click()
}
checkClick() {
console.log('clicked')
}
render() {
return (
<div>
<button ref={this.button} onClick={this.checkClick}>Click me!</button>
</div>
)
}
}
export default Test
First of all, I do not recommend you to create functions outside of React component class. In your case, you are not able to use it like this.checkClick because the checkClick function is declared outside of your React component.
The second thing, working with real DOM inside of React is basically, let's say, antipattern. React provides virtual DOM and works with it, so, I recommend you to learn about React ref API.
For your case, you can use the lifecycle componentDidMount() method. It is being called (AUTOMATICALLY, for sure) when the component has finished its first render, so, all refs are already available here and all children elements are beind mounted and present in DOM.
import React from "react"
export default class Test extends React.Component {
componentDidMount() {
document.getElementById("button").click()
}
checkClick() {
console.log("clicked!")
}
render() {
return (
<div>
<button id="button" onClick={this.checkClick}>click</button>
</div>
)
}
}
or, using refs
import React from "react"
export default class Test extends React.Component {
componentDidMount() {
this.button.click()
}
checkClick() {
console.log("clicked!")
}
render() {
return (
<div>
<button ref={button => this.button = button} onClick={this.checkClick}>click</button>
</div>
)
}
}
Use componentDidMount for that,
import React from 'react';
class Test extends React.Component {
componentDidMount(){
this.checkClick();
}
checkClick () {
console.log("clicked");
}
render() {
return (
<div>
<button id="button" onClick={this.checkClick}>click</button>
</div>
)
}
}
export default Test;

How to use refs with react-redux's connect HOC on two components?

I have two components which both use the connect HOC.
import {connect} from "react-redux";
import ComponentB from "./ComponentB";
class ComponentA extends Component {
render(){
return {
<div>
<button
onClick={this.refs.ComponentB.showAlert()}
>
Button
</button>
<ComponentB
ref={instance => {
this.ComponentB = instance.getWrappedInstance();
}}
/>
</div>
}
}
}
export default connect(mapStateToProps, {}, null, {withRef: true})(ComponentA)
Having ComponantA with the connect HOC gives me the error "TypeError: Cannot read property 'getWrappedInstance' of null"
export default ComponantA;
Not using the HOC would not give me this error.
import {connect} from "react-redux";
class ComponentB extends Component {
showAlert = () => {
alert("Please Work");
}
render(){
return {
<div>ComponentB</div>
}
}
}
export default connect(mapStateToProps, {}, null, {withRef: true})(ComponentB)
React.createRef was introduced in React 16.3 and is supposed to be used like:
this.componentBRef = React.createRef();
...
<button
onClick={() => this.componentBRef.current.getWrappedInstance().showAlert()}
>
Button
</button>
<ComponentB
ref={this.componentBRef};
}}
/>
As explained in this answer, the pattern used in createRef allows to lazily access a ref through current property because this.componentBRef.current is initially null.
Since Redux is in use, there's a chance that the interaction between components should be performed via Redux instead.

Where to bind actions to a react component

Is it bad practice to connect / bind actions (and for that matter, state) to a component in the same file in which you are defining said component? If so, is the suggested practice to create a container component (as outlined here)? If that is the case and I want to drill props from a parent component to a child component that needs actions and state connected to it, and thus a container, how do I do this? Thanks.
If this said component is and will be the only one using the connected state and actions, no it is not a bad practice. Even this is not the case, you can connect multiple components to your store. But, wouldn't be easy to use a container component and pass your needed state parts and some of your action creators to the related child components?
import React from "react";
import ReactDOM from "react-dom";
import { connect } from "react-redux";
import { anAction, anotherAction } from "./actions/";
class ContainerApp extends React.Component {
state = {
maybeSomeLocalState: "",
}
render() {
const { aState, anAction, anotherState, anotherAction } = this.props;
return (
<div>
<Child
aState={aState}
anAction={anAction}
/>
<Child2
anotherState={anotherState}
anotherAction={anotherAction}
/
</div>
);
}
}
const mapStateToProps = state => ({
aState: state.aState,
anotherState: state.anotherState,
});
export default connect( mapStateToProps, { anAction, anotherAction } )(ContainerApp);
const Child = (props) => (
<div>
<p>{props.aState.someValue}</p>
<button onClick={props.anAction}>Do something</button>
</div>
);
const Child2 = (props) => (
<div>
<p>{props.anotherState.someValue}</p>
<button onClick={props.anotherAction}>Do another thing</button>
</div>
);

Where in redux-react app would I include my stateful presentational component? In components or containers folder?

Search Component:
import React from "react";
import SearchResults from "../SearchResults";
import PropTypes from "prop-types";
class Search extends React.Component {
state = {
value: ""
};
handleChange = event => {
let value = event.target.value;
this.setState({ value });
this.props.performSearch(value);
};
handleSubmit = event => {
event.preventDefault();
};
render() {
return (
<div>
<h1>The Guardian Search App</h1>
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</form>
<div>
<SearchResults articles={this.props.articles} />
</div>
</div>
);
}
}
Search.propTypes = {
performSearch: PropTypes.func,
articles: PropTypes.array
};
export default Search;
Search Container:
import React from "react";
import Search from "../../components/Search";
import { API_KEY } from "../../../config";
import fetchArticles from "../../api";
class SearchContainer extends React.Component {
state = {
articles: []
};
performSearch = event => {
return fetchArticles(event).then(data =>
this.setState({ articles: data.response.results })
);
};
render() {
return (
<Search
performSearch={this.performSearch}
articles={this.state.articles}
/>
);
}
}
export default SearchContainer;
I am currently trying to get my head around redux so transitioning this into react-redux version. I've got a Search Container whereby I am doing mapStateToProps and will soon write mapDispatchToProps as well. But if my Search component also includes state, do I then do another Search Container to then map its state to props?
The state required in your Search component is directly linked and required by the input element that you have rendered as a child. Therefore, the value state in the Search component should stay within the component and not be associated with Redux.
There is no "correct" way of doing this, mainly preference and design pattern. Since you have state in the Search component that you don't want to be associated with Redux, I would hook the SearchContainer component into your Redux store for providing the array of article objects which can then be passed to the base Search component as a prop and leave that component entirely unaware that Redux even exists.

Resources