class SearchInput extends React.Component {
constructor(props) {
super(props);
this.searchInputRef = React.createRef(); // 👈️ LOOK HERE
}
onFormSubmit = (e) => {
e.preventDefault();
// const query = e.target.querySelector("#searchInput").value; // 👈️ LOOK HERE
const query = this.searchInputRef.current.value;
console.log(query);
};
render() {
return (
<form onSubmit={this.onFormSubmit}>
<div className="input-group-text">
{this.props.label}
<input
type="text"
className="form-control"
id="searchInput"
aria-describedby="emailHelp"
placeholder="Search"
ref={this.searchInputRef}
/>
<button type="submit" className="btn btn-primary">
<i className="fas fa-search"></i>
</button>
</div>
</form>
);
}
}
I'm very new to ReactJS, but I'm having hard times with it, I have two questions about my component above:
on the first // 👈️ LOOK HERE comment above, you see, I'm saving the references to the class instance itself (in the constructor) which leads to two downsides:
The constructor will become very messy later when I add 7 or 8 references inside of it, which makes it non-clean code.
We're saving the reference to the object body of the class instance, do you think this is a clean-code? maybe there should be something in React that allows me to store all the references inside one property may be called "refs", so the instance of that class would look like the following:
{
refs: {
searchInputRef: ...
// later
buttonRef: ...
button2Ref: ...
iconRef: ...
}
state: ...
// the rest of the component object
}
Which is more cleaner if you ask me.
If I'm wrong, please let me know.
on the second comment // 👈️ LOOK HERE of course you can see I don't actually need a reference in my case, so why I'm using ref sys~? I can simply get the input from e.target.querySelector("#searchInput") as simple as it looks like, why folks are always saying it's a shame and a bad practice to use my beloved querySelector to reference DOM elements when using React?
Well, I think the people you mentioned (those who say using DOM is embarrassing) are completely wrong!
They have probably never read the official ReactJs documents and are merely expressing their personal (and completely wrong) opinion.
Stop Overuse Refs!
According to the documentation on the ReactJs website, overuse of the Refs is completely wrong. ReactJs recommends that you do not even use open() or close() modals.
So the best option we can choose is to use DOM.
But this does not mean that ReactJs has put a useless thing in its library facilities. Not at all.
So when to Use Refs?
There are some great cases where using Refs is very economical. For example, to focus on fields or create multiple animations.
In my opinion, there is nothing that Refs can not do. And on the other hand, there is nothing that can not be done with DOM. Both are fully functional.
What matters is the performance and efficiency of each.
DOM is a proven thing in the web world, but according to ReactJs, overuse of Refs can be harmful.
Anyway, this is a general overview of Refs and DOM that I would like to share with you.
I hope other people give you suggestions on how to use Refs better.
Finally, there is another important issue.
I understand from your question that you care a lot about the performance of your program. But I was wondering why you do not use functional components instead of class components?
Using functional components can greatly enhance the performance, efficiency and speed of your program. I hope you read about it and improve the performance of your program by migrating to functionals.
Please Read This Articles:
Components and Props
Introducing Hooks
React Function Components
At first // 👈️ LOOK HERE,
You could have a function to create ref, to distinct them i prefer an id.
class SearchInput extends React.Component {
constructor(props) {
super(props);
}
refs = {} // 👈️ LOOK HERE
getRef(id) { // 👈️ LOOK HERE
if (!this.refs.hasOwnProperty(id)) {
this.refs[id] = React.createRef();
}
return this.refs[id];
}
render() {
const
return (
<form onSubmit={this.onFormSubmit}>
<div className="input-group-text">
{this.props.label}
<input
type="text"
className="form-control"
id="searchInput"
aria-describedby="emailHelp"
placeholder="Search"
ref={this.getRef(id)} // 👈️ LOOK HERE, id - you decide
/>
<button type="submit" className="btn btn-primary">
<i className="fas fa-search"></i>
</button>
</div>
</form>
);
}
}
At second // 👈️ LOOK HERE, i think this question has been asked you should do a search for it.
Related
I'm self-teaching React and was just wondering if someone could clear something up for me.
I have this component, which seems to be doing everything I need it to:
const Projects = ({ projectData }) => {
const { url } = useRouteMatch();
return (
{projectData.map((project) => (
<div className="project-container" key={project.id}>
<div className="project-image">
</div>
<div>
<h2>{project.name}</h2>
<p>{project.description}</p>
<div>
<Button class="button link_right relative" linkTo={`${url}/${project.id}`} btnText="Explore" />
</div>
</div>
</div>
))}
);
};
export default Projects;
While watching tutorials and reading documentation I'll typically see Function and Class Components but not whatever this is:
const ComponentName = () => {
So, my questions are:
What sort of component is my example known as
What purpose does it
serve when compared to a Function Component or a Class Component,
How would a Function Component or a Class Component need to look in
order to do everything that my example component is currently doing.
Thanks!
Making instance of class is too slow, because of calling constructor and inheritance. Functional components are just functions, there are no such overheads.
In addition, there is how to treat this. In class, entity of this is often unclear and that confused us. Arrow function reduce it, but using class, we must use this. this caused complicated management of state too. And class object has state itself, so it was troublesome.
Function, defined carefully, is easy to keep purity. It has no state itself. It means that state management is not bother us. Data flow is cleared.
I am trying to create a website by using GatsbyJS, and I got stuck whenever I need to set a onClick event to toggle a class in one of my components. As a beginner with react and gatsby, I'm having a hard time to do it.
So essentially I want to make the following JS code in React/GatsbyJS:
const hamburger = document.querySelector('.burger_menur');
hamburger.addEventListener('click', function(){
this.classList.toggle('open');
});
The following code is my current code in Gatsby component. Have to say, I am using GSAP to make an animation.
This is my code:
import React from 'react';
import { Tween, Timeline } from 'react-gsap';
import '../styles/burger.scss'
const Burger = () => (
<Timeline
target={
<div className='burger'>
<div className='burger_menu'>
<div className='bar half start'></div>
<div className='bar'></div>
<div className='bar half end'></div>
</div>
</div>
}
>
<Tween from={{ opacity: '0', marginRight: '0rem' }} to={{ opacity: '1', marginRight: '5rem' }} ease="Back.easeOut" delay={2}/>
</Timeline>
);
export default Burger
Hopefully someone can help me out with this.
If you're going to go with React, don't manipulate the DOM directly.
More specifically, don't try to act directly on any part of the DOM generated by React.
Here, you're using plain DOM manipulation to attach your event to elements generated by React (also, there's a typo in your class name):
const hamburger = document.querySelector('.burger_menur');
hamburger.addEventListener('click', function(){
this.classList.toggle('open');
});
The thing is, while it may sometimes work, React will regenerate new elements for your menu when it deems it necessary, and your events listeners will be lost.
You have to do it "the React way":
...
<div className='burger'>
<div className={`burger_menu ${this.state.isOpen? ' open' : ''}`} onClick={() => this.setState({ isOpen: !isOpen })}>
<div className='bar half start'></div>
<div className='bar'></div>
<div className='bar half end'></div>
</div>
</div>
...
Don't forget to initialize your state with { isOpen: false }
Clicking the div will toggle this.state.isOpen, which is used to decide whether the class-name will be 'burger_menu' or 'burger_menu open'.
Note: There are more elegant ways to work with classlists when they get longer, but your component being simple and for the sake of clarity, a string template will more than do.
If any of this sounds confusing, please read through the official tutorial Intro To React, it's very well explained and covers everything needed here.
If you're already comfortable with this and want to know more about handling events in React, the docs has you covered once again: Handling Events
Perhaps not the best place to ask this question. If not, please point me down the trail I need to go.
I've started working with ReactJS to freshen up programming vernacular and I believe I have the hang of the principle concepts; however, while learning a new programming language I have found MANY MANY different ways to do things (such as the case with computer programming). I have a simple input component I want to use in my design:
class TextField extends Component{
constructor(props,context){
super(props,context);
this.state = {errmsg: ''}
this.setError = this.setError.bind(this);
}
setError(errormessage){
this.setState({
errmsg: errormessage
})
}
render(){
var inpdiv = this.props.id + "_div";
var errdiv = this.props.id + "_err";
return(
<div id={inpdiv}>
<label for={this.props.id}>{this.props.label}
<input type="text" id={this.props.id} name={this.props.id} />
<div id={errdiv}>{this.state.errmsg}</div>
</label>
</div>
)
}
}
export default TextFieldest;
Notice the setError function. I call this function from another (parent) component:
class Form extends Component{
constructor(props,context){
super(props,context)
this.emailaddress_ref = React.createRef();
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(){
this.emailaddress_ref.current.setError('Testing the Error Area of the Test Component');
}
render(){
return(
<div>
<Test id="emailaddress" ref={this.emailaddress_ref} label="Enter Email Address" />
<Button btntext="Press Me!" handleclick={this.handleSubmit} />
</div>
)
}
}
export default Form;
My question is:
Is this the most accepted way to handle changing the state of a child component or am I going down a bad path here?
You might rather want to pass down the error function via props, since it decouples one component from another, and it doesnt lead to a point where if you render two or more components you will have a mess handling refs in secenarios where you really dont need them. refs are rare in their need, and while you can bend them your way, its much saner to just send things via props. In general using ids for reusable components either is not a great idea.
You will need to realize in your case for example who should handle the error and to what extent. Is you text input semi autonomous with regards to input validation? If you reuse is elsewhere will you believe that its validation should be handled by parent? Both yes and no are valid answers, but you need to understand who owns the flow in your app.
EDIT: While Sung Kim's answer is correct for the original scenario, I forgot to add that this behaviour (of selecting the next item from the list) can be toggled by some other key, for instance ArrowDown, in which case the tabIndex would not be of much help initially at least.
`````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
I'm trying to work on a dropdown component that has two separate (sibling) functional components. The first one is a regular <input> that will take in a value.
The second one is a <ul> that will display the results.
The flow is that initially only the <input> is displayed, when you type in and get results back from the database, then the <ul> gets rendered.
The above functionality is done, however, what I want to accomplish now is that when I'm done typing (because I'm satisfied with the results I see) and I hit tab, then the first item on the results list (precisely a <a> within the <li>) gets focused, and then if I continue to hit tab the next item on the last will focus and so on until it reaches the final item.
So, essentially the focus action could come from either hitting tab on the input or, from the current list item (if it has already been focused).
I've been thinking about the cleanest approach to get this to work. I thought perhaps using ref via createRef and forwardRed could be a good idea, but honestly I can't wrap my head around it for the time being so I thought I'd reach out for help.
This is essentially what it looks like (everything is working as intended, I cut out pretty much all the logic to strip it down to the basics and focus on the main issue here, which is, well, focus...).
Parent Component:
class Parent extends React.Component {
componentDidMount() {}
handleInternalKeyPress = (e) => {
if (e.key === 'Tab') {
e.preventDefault()
// do something?
}
}
render() {
return (
<section>
<section>
<DropdownInput
handleTextChange={this.props.handleTextChange}
handleKeyDown={this.handleInternalKeyPress}
/>
<DropdownResults
results={this.props.results}
handleKeyDown={this.handleInternalKeyPress}
/>
</section>
</section>
)
}
}
Input Component:
const DropdownInput = props => (
<Input
onChange={e => props.handleTextChange(e)}
onKeyDown={e => props.handleKeyDown(e)}
type="text"
/>
)
Results component (<ul>):
// Maybe this should be a React.forwardRef() instead of
// an arrow function, but I'm not sure if this is the
// best/most elegant approach
const DropdownResults = props => (
<ul>
{props.results.map((result, i) => (
<li key={result.resultIdKey}>
<a
// perhaps a ref should go in here?
onKeyDown={e => props.handleKeyDown(e)}
role="link"
tabIndex={i}
>
{result.resultTitleDisplayKey}
</a>
</li>
))}
</ul>
)
Again, the compoenents are quite a bit more complex than this, but this is the basic idea of how they work.
It would also be ideal to get a hold of the focused item to set custom styles to it, for instance.
I've been giving it some thought but this one has really got me, particularly because I want to adhere to best/latest React practices so any help that can be provided will be much appreciated!
I've never used tabIndex but played around after reading some articles.
It looked like setting the tabIndex={0} worked instead of increasing it using i.
const DropdownResults = props => (
<ul>
{props.results.map((result, i) => (
<li key={result.resultIdKey}>
<a
// perhaps a ref should go in here?
onKeyDown={e => props.handleKeyDown(e)}
role="link"
tabIndex={0}
>
{result.resultTitleDisplayKey}
</a>
</li>
))}
</ul>
);
For some reason Google documentation (Using tabindex) says using tabIndex greater than 0 is an anti-pattern without much explanation (as well as this older blog post, which doesn't explain why not either)
even though MDN documentation doesn't say anything about using tabIndex greater than 0 being an anti-pattern.
But for now setting all values of tabIndex=0 seems to work.
You can fork the code.
I have the following code:
#autobind
setName(name){
this.setState({name: name});
}
#autobind
setLocation(location){
this.setState({location: location});
}
#autobind
setReference(reference){
this.setState({reference: reference});
}
All the functions placed above have a similar structure, and I would like to know if there is a good practice in React.js to avoid having to repeat myself to set different states.
Thanks in advance.
You could make a function that takes the object as a value, rather than the key value and pass it to setState
setValue(object) {
this.setState(object)
}
and use it like:
<div onClick={() => this.setValue({ reference })} />
but then you may as well just call setState directly.
<div onClick={() => this.setState({ reference })} />
So really you don't need any of those functions because setState is that function.
However, this generalized setValue function could be useful when passing to children.
<Child setParentState={this.setValue} />
and use it
<div onClick={() => this.props.setParentState({ reference })} />
Though I admit I've never done anything like that. Seems to give too much control to child elements, but used sparingly should be fine.