Pretty new to React, and I have this issue where 2 of my components are fairly similar, but different enough to not be the same.
I looked up a way to compose the components and avoid duplications, and with Mixins out of the way, I encountered HOC, which I think can be pretty powerful, yet confusing for somebody like me who's not yet familiar with React and its inner workings.
So I have my main component(wrappee) which will then be wrapped. In turn that component renders a child component (in my case a textarea for one of the wrappee component, the other one being an input field).
One of the reasons why I'd like to use HOC is that I bind event listeners to the text input, and so need to be able to access it from the HOC.
Textarea ---- InputController ---- InputHOC
Input ---/
In practice I have managed a way to communicate the DOM element back to the HOC, using a callback in ref. But I feel it's pretty dirty, as I have to have 2 callbacks:
InputController:
return (
<div>
{textareaHint}
<div className='longtext-input-wrapper'>
{textareaComponent}
</div>
</div>
)
textareaComponent
return <TextareaAutosize
ref = {
(c) => {
this._input = c
}
}
className={classList}
minRows={MIN_ROWS}
/>
and then in InputHOC:
<div className={submitButtonClass}>
<Button clickHandler={_buttonClickHandler.bind(this)} ref='submitButton'>
<span className='button-text'>Ok</span>
<span className='button-icon'>✔</span>
</Button>
<InputComponent ref={
(item) => {
if (item && !this.input) {
this.input = item._input
}
}
}
/>
</div>
And then I can access this.input in componentDidMount:
const inputNode = ReactDOM.findDOMNode(this.input)
It does really feel hacky, so I was wondering if there was a better way to deal with this?
Thanks a lot for your input
#Jordan is right, this is not using the HOC pattern. A good example of this pattern can be found here: https://gist.github.com/sebmarkbage/ef0bf1f338a7182b6775. You can think of a HOC as a superclass for the component that it wraps, but it's not actually a class. A HOC is a function that takes a react component and returns a new one with the desired enhancements.
What you are doing is using ref callbacks to link together all of your components and making other components aware of things other than their direct children, which is definitely not recommended. In your case, I don't see why you shouldn't place everything from InputHOC into InputController. Then, define the functions that you want to bind to the input in TextareaAutosize in InputController and pass them as props. It would look something like this:
InputController:
class InputController extends React.Component {
handleChange() {
// Note that 'this' will not be set to the InputController element
// unless you bind it manually
doSomething();
}
render() {
return (
<Button clickHandler={_buttonClickHandler.bind(this)} ref='submitButton'>
<span className='button-text'>Ok</span>
<span className='button-icon'>✔</span>
</Button>
<div>
{textareaHint}
<div className='longtext-input-wrapper'>
<TextareaAutosize callback={this.handleChange} />
</div>
</div>
);
}
}
TextareaAutosize
class TextAreaAutosize extends React.Component {
render() {
return (
<textarea onChange={this.props.onChange}>
Some text value
</textarea>
)
}
}
Related
I've hot React component which returns input tag. Can you please explain what is going on at the eighth line ref={element => element && (element.onChange = onChange)}? I
import React from 'react';
export default function MyInput({
onChange,
...rest
}) {
return (
<input
{...rest}
ref={element => element && (element.onChange = onChange)}
/>
);
}
React's ref is used to access the DOM directly, and in general is recommended to use as less as possible. The point of functional refs, and keep in mind that they're deprecated, is to assign the element into a class component's variable. e.g.:
Class MyComponent extends Component {
constructor(props) {
super(props);
this.inputRef = null;
}
...stuff
render() {
...stuff
<input ref={element => this.inputRef = element} />
}
}
Then, you could do something like:
this.inputRef.current.style.color = 'blue';
In your case, there is no need for this. If you want to assign the onChange you get from props, just do this:
<input {...stuff} onChange={onChange} />
Read more about React refs here.
As for element && element.onChange, it's designed to make sure that element exists before accessing it's onChange property. Another way to do it, using optional chaining (only avaliable in react-scripts v3.3 and above), is this:
element?.onChange
Refs are used to access DOM elements
The value of ref differs depending on the type of node:
When the ref attribute is used on an HTML element, the ref created
in the constructor with React.createRef() receives the underlying
DOM element as its current property.
When the ref attribute is used on a custom class component, the ref
object receives the mounted instance of the component as its
current.
They are used in cases where we want to change the value of a child component, without making use of props and all. But in your case, i think you have no need to use ref because you simply wants to assign onChange that you received from props.
I wonder if it is fine to predefine some JSX and use it multiple times in different components.
const saveButton =
<div class="u-mth u-textRight">
<Button variant="flatBlue">Save</Button>
</div>;
const test = <div>{saveButton}</div>;
Is there any downside compared to a normal functional react component?
export const SaveButton = () => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">Save</Button>
</div>
);
const test = <div> <SaveButton /> </div>
And what about this one instead of functional with react props:
const saveButton = (text: string) => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">{text}</Button>
</div>
);
const test = <div> {saveButton(text)} </div>;
First one is simply just jsx, it's not a component.
Second one is a stateless component, which is fine as well but you have not used any props.
Third one is also just a function not a component as you have not used props. What I would do is as #estus recommended in answer.
But please also view this link which says they way you have approached is actually faster.
React component (snippet 2) will appear as in React devtools as <SaveButton>...</SaveButton>, while other options won't.
React component (snippet 2) is the way it's usually done. If a component needs to expose dynamic behaviour, parameters should be passed as props:
const SaveButton = ({ text }) => (
<div class="u-mth u-textRight">
<Button variant="flatBlue">{text}</Button>
</div>
);
and
<SaveButton text={text} />
Helper function (snippet 3) is the way how the performance of React component can be improved, by calling it directly. It can be considered preliminary optimization, unless proven otherwise.
As long as element hierarchy doesn't expose dynamic behaviour, the definition of React elements as a variable (snippet 1) has no downside under normal circumstances. If there's a possibility that dynamic behaviour can be necessary in future (custom or localized text), it will require refactoring.
It is just declaring variables. Nothing else. In this case, using ES6 and JSX.
It is the same thing as 1. just as function. This function returns what you declared under 1. Using ES6. No downsides.
The same as 2. with arguments object, actually passing parameter to function using ES6 and Type Script.
function saveButton(props) {
return <div class="u-mth u-textRight">
<Button variant="flatBlue">{props.text}</Button>
</div>;
}
const element = <saveButton text="Save" />;
ReactDOM.render(
element,
document.getElementById('root')
);
This is the way using props and pure function.
I can't seem to grasp the understanding of why higher order components are highly valued over the regular components? I read a tutorial on them and that higher order components are good because they: 1) Allow code re-use, logic and bootstrap abstraction. 2) Able to do render highjacking. 3) Able to abstract state and manipulate them. 4) Able to manipulate props. Source: link
An example of a higher order component in code was shown there as:
function refsHOC(WrappedComponent) {
return class RefsHOC extends React.Component {
proc(wrappedComponentInstance) {
wrappedComponentInstance.method()
}
render() {
const props = Object.assign({}, this.props, {ref: this.proc.bind(this)})
return <WrappedComponent {...props}/>
}
}
}
These look almost the same exact code as a regular class definition that receives props and you are still able to "manipulate props" and "manipulate state" inside that class
class Something extends React.Component {
constructor(props) {
super(props);
this.state = { food: 'no_food_received_yet' }
}
componentDidMount() {
this.setState({ food: 'apple' });
}
render() {
return (
<div>
<p>{ this.state.food }</p>
<h2>{ this.props.food }</h2>
</div>
);
}
}
Actually I didn't get to manipulate or mutate the props but I can just receive them, apply them to state and output that state.
This is not to bash on higher order components---this is actually the complete opposite. I need to understand where I am wrong and why I should integrate higher order components into my react app.
HOCs are absolutely useful, but they're useful in the same way any "higher order" function is.
Consider the following component:
let Button = props => <button style={{ color: props.color }} />
You could make another component called BlueButton:
let BlueButton = props => <Button color="blue" />
There's nothing wrong with that, but maybe you want any component to be able to be blue, not just a button. Instead we can make a generic HOC that "blueifies" the passed component:
let blueify = Component => props => <Component {...props} style={{ color: 'blue' }} />
Then you can make blue buttons, blue divs, blue anything!
let BlueButton = blueify(Button)
let BlueDiv = blueify(props => <div {...props} />)
Imagine you had an app where certain screens were private and only available to authenticated users. Imagine you had 3 such screens. Now on each screen's container component you can have the logic to check if the user is authenticated and let them through if they are, or send them back to login when they are not. This means having the exact same logic happen 3 times. With a HOC you can code that logic just once and then wrap each private screen in with the HOC thus giving you the same logic over and over, but the code only needs to exist in one place. This is an example of great code reuse that HOCs offer.
Higher order components are more generalized, and so in theory can be applied to a broader number of cases. In the more general sense, higher-order components (and higher-level languages) tend to be more expressive.
In your case, the difference is readily apparent. The non-generalized (lower-order) component has hard-coded HTML in it. This is programming 101; constant declarations like PI are preferred over hard-coded declarations like 3.14159 because they give meaning to magic numbers and allow one point of modification.
A simple example of a higher order "component" (in this case a higher order function) is a sort function that takes as one of its arguments an ordering function. By allowing the ordering to be controlled by an outboard function, you can modify the behavior of the sort without modifying the sort function itself.
I am trying to figure out the proper "react" way to pass in an optional prop that is an Element to a container component, that is handled differently from the children of that component.
For a simple example, I have a Panel component, which renders its children, that also has an optional "title" prop (which is an element rather than a string, for the sake of the example) that gets specially rendered (put in a special spot, with special behaviors in while maintaining the abstraction.
One option is to have a component which is pulled out of the children and rendered specially:
<Panel>
<Title> some stuff</Title>
<div> some other stuff</div>
</Panel>
But it seems wierd to have the children pulled out and handled separately like that.
How is this normally handled in react, and am I even thinking about this the right way
You don't need to do anything special. Just pass the title component as a prop, and then use {this.props.title} wherever you want it to be rendered:
class Panel extends React.Component {
render() {
return <div>
{this.props.title}
<div>Some other stuff...</div>
</div>;
}
}
class App extends React.Component {
render() {
var title = <Title>My Title</Title>;
return <Panel title={title}/>;
}
}
If you don't pass any value for the title prop (or if the value is false, null, or undefined) then nothing will be rendered there.
This is a fairly common pattern in React.
you can do something like this
render(){
<div>
{this.props.title ? this.props.title : null}
{this.props.children}
</div>
}
basically if you pass a title element as a prop then create it as an element and render it. else just put in null...
to create it you would do something like this.
<Panel title={<Title>Something Here</Title>}
<div> something here</div>
</Panel>
This is generally how react should handle optional child components
When you need an attribute from your optional prop, you will have to check first if the prop was delivered. Otherwise, you will get a:
TypeError: Cannot read property 'yourPropProperty' of undefined
In conditional rendering context (depending on my optional this.props.ignore array), this won't work:
{!this.props.ignore.includes('div')) && (
<div>
Hey
</div>
)}
Instead, you should do:
{(!this.props.ignore || !this.props.ignore.includes('div'))) && (
<div>
Hey
</div>
)}
One thing you can do is have default props (usually initialised to a no-op) for your component.
For example, if you want to have an optional function prop:
class NewComponent extends React.Component {
...
componentDidMount() {
this.props.functionThatDoesSomething()
}
}
NewComponent.defaultProps = {
functionThatDoesSomething: () => {}
}
This way, parent components can choose to pass the function prop or not and your app won't crash due to the error
this.props.functionThatDoesSomething is not a function
.
I am getting confused with props and refs in ReactJS. Can anybody explain me the difference between them with proper example.
Thanks in advance.
Props are used to pass parameters which should be static (on the contrary of state). For example you can pass a size or name from an upperView to a lowerView (nested views);
Interesting part on props: https://facebook.github.io/react/docs/transferring-props.html
refs are used to acces the real DOM and not the virtual DOM of react. It's needed when you need to access the real DOM.
This part is interesting :https://facebook.github.io/react/docs/more-about-refs.html
this.setState({userInput: ''}, function() {
// This code executes after the component is re-rendered
React.findDOMNode(this.refs.theInput).focus(); // Boom! Focused!
});
The example above show you how to access a DOM element properly when the state is updated.
Hope it helps.
For sure there are differences between, one mostly use for selecting the DOM, one for getting data as a property, I create the image below and explain few major differences:
Also this the sample of grandparent, parent and child components which using ref and props to pass data, it's a good example to understand when and how they get used, please pay attention how ref helping to get in deeper component by referencing to the element:
function Child(props) {
return (
<div>
<input ref={props.inputRef} />
</div>
);
}
function Parent(props) {
return (
<div>
My input: <Child inputRef={props.inputRef} />
</div>
);
}
class Grandparent extends React.Component {
render() {
return (
<Parent
inputRef={el => this.inputElement = el}
/>
);
}
}
Those are two different things.
Props: Use them to pass any parameters to your component.
Refs: Shortcut for references. These are references to your DOM elements. Use them if you need to access raw DOM element for some reason. For example to add custom event handler via .addEventListener() function.
in addition to the answer above by François Richard, u might wanna read:
https://github.com/uberVU/react-guide/blob/master/props-vs-state.md
because the confusion is more often between state and props.
good luck