How to select specific element in react.js - reactjs

I want to select specific element with className "material-icons-outlined" and add new class to that element
In javascript i would do it like this
document.querySelectorAll(".material-icons-outlined").forEach(icon => {
icon.classList.add("notranslate");
})
But in react that doesn't work though, so how to do that in a react way?

You can still do that in React, just put those lines in useEffect:
useEffect(() => {
document.querySelectorAll(".material-icons-outlined").forEach((icon) => {
// check if already has the class
if (!icon.classList.contains("notranslate"))
icon.classList.add("notranslate");
});
});

Checkout ref or useRef in reactjs It is your answer.
class App extends React.Component {
componentDidMount() {
this.yourRef = React.createRef()
}
render() {
return (
<div>
<div id="divR" ref={this.yourRef}>...</div>
</div>
)
}
}

Related

How to limit queryselector to a react component

I have a react component with a list of child-components. In the child-component I want to target a specific DOM element e.g., to change the color in its ComponentDidMount method. How would I do this?
Parent component
export class ListComponent extends Component<...> {
render(): ReactNode {
return (
<div>
<ListItemComponent key="123"/>
<ListItemComponent key="456"/>
<ListItemComponent key="789"/>
</div>
);
}
}
Child component
export class ListComponent extends Component<...> {
componentDidMount(): void {
// const elementToChange = document.queryselector(".toTarget"); // Only works for the first element as it only targets the first on the page
const elementToChange = THISREACTCOMPONENT.queryselector(".toTarget");
elementToChange.style.backgroundColor = "123123";
}
render(): ReactNode {
return (
<div>
<div className="toTarget">
</div>
);
}
}
So, the question is, what should be instead of THISREACTCOMPONENT? How to target an element exclusively within the react component?
use a react ref.
Refs were created so you won't have to use queryselector, as interacting directly with the dom may lead to react bugs further down the line.
export class ListComponent extends Component<...> { {
constructor(props) {
super(props);
this.myRef = React.createRef(); // Get a reference to a DOM element
}
componentDidMount(): void {
const elementToChange = this.myref.current;
elementToChange.style.backgroundColor = "123123";
}
render() {
return (
<div>
<div className="toTarget" ref={this.myRef}> // binds this element to the this.myref variable
</div>
)
}
}
You could use Document.querySelectorAll to get all matching elements
document.querySelectorAll returns an array of matching element.
Then you would do it like so:
componentDidMount(): void {
const elements = document.querySelectorAll(".toTarget");
elements.forEach((el) => {
el.style.backgroundColor = "123123";
});
}

Add fade-in animation to a list element in React

I have the following code that display a table's data from Laravel using axios in React.
The data is displayed in real time. How can I add a fade-in animation each time a new element is added ? https://socket.io/ shows exactly what I want to do in the example on the right.
Note that the element in the li tag is added from an event that is fired up from a creation controller.
The component :
import React,{Component} from 'react';
import axios from 'axios';
import { Link } from 'react-router-dom';
import Echo from "laravel-echo";
class Patient extends React.Component {
constructor(props) {
super(props)
this.state = {
patients : [],
};
}
componentDidMount() {
axios.get('api/patients')
.then(response => {this.setState({patients: response.data})})
.catch(err => console.log(err));
window.Echo.channel('home')
.listen('NewPatient', newPatientData => {
this.setState({
patients: this.state.patients.concat(newPatientData)
})
}, e => {
console.log("Error", e)
})
}
render() {
return (
<div>
<ul> { this.state.patients.slice(0).reverse().map(patient => <li>{patient.nom}</li>)} </ul>
</div>
)
}
}
export default Patient;
You can do this pretty easily with CSS animations. I've created an example below for you and if you check out the CSS, you'll see the keyframe animation which is then used by the .fadeIn selector and that class is then applied to the <li> element.
https://codesandbox.io/s/dreamy-frog-r6sr8?file=/src/styles.css

React - what are the steps to get data from api and render it?

I am building a site just like stackoverflow.com. I want my home page to display top questions. For that, I have sample questions on the backed. Now, I want to display only the question and tags from the questions array.
The code is in the image
I have made axios connection for that:
const instance = axios.create({
baseURL: "https://2w2knta9ag.execute-api.ap-south-1.amazonaws.com/dev", });
instance.defaults.headers.post["Content-Type"] = "application/json";
To connect it, I wrote the command: instance.get("/questions)
Now, how do I display only the question and tags??
EDIT:
On using the code given bellow, my js file now becomes:
import React from 'react';
import instance from '../../api';
class QuestionList extends React {
componentDidMount() {
instance
.get("/questions")
.then((res) => {
this.setState({ data: res.data });
});
}
render () {
const { data } = this.state;
return <div>
{
data && data.map(d => {
return <div>question: {d.question}, tags: {d.tags}</div>;
})
}
</div>
}
}
export default QuestionList;
But, this is just making my site in a loading state, and it gets hanged!!
If I understood correctly, you want to get an array only with the tags and the question. if so, you can use Array.prototype.map for this
const questions = result.map(({ question, tags }) => ({ question, tags }))
First you export the axios instance so that it can be used from other components.
Now you can send the api request in componentDidMount and update your component's state with the data.
And in render function, you just get the value from state and display.
If you are new to react, learn React Hooks and know that componentDidMount method is the best place to send api requests.
For Example:
import React from 'react';
import instance from '../../api';
class QuestionList extends React.Component {
constructor() {
super();
this.state = {
data: [],
};
}
componentDidMount() {
instance.get('/questions').then((res) => {
this.setState({ data: res.data });
});
}
render() {
const { data } = this.state;
return (
<div>
{data &&
data.map((d) => {
return (
<div>
question: {d.question}, tags: {d.tags}
</div>
);
})}
</div>
);
}
}
export default QuestionList;

Conditional Rendering,use-timeout Invalid hook call React

When check is true I want to display Next button.I get errors like unexpected token,invalid hook call.
Please help me.Thanks in advance.
import React from "react";
import useTimeout from "use-timeout";
class App extends React.Component {
state = { check: true };
handleCheck = () => {
this.setState({ check: !this.state.check });
};
render() {
useTimeout(() => {
this.handleCheck();
}, 10000);
return (
<div>
{
if(this.state.check){
return <button>Next</button>
}
}
</div>
);
}
}
export default App;
do this instead:
<div> {this.state.check && <button>Next</button> </div>
and remove useTimeout you don't need it and you CANT use it either as it's a hook and you're using a class component. You should trigger it by onClick instead or if you insist on using a timeout use setTimeout but I wouldn't advise using that inside render
use a timeout like this:
componentDidmount() {
setTimeout(() => {
this.handleCheck();
}, 10000);
}

React - Getting refs to wrapped class components

I have a map component that contains a child sidebar component. I am trying to do a relatively simple task of scrolling to the place in the list of places in the sidebar when it's map marker is clicked on. But, because the sidebar needs to be wrapped in withRouter and connect, I'm unable to set a ref (ref) => this.sidebar = ref in the map component.
export class Map extends React.Component {
...
handleClick() {
this.sidebar.scrollToPlace(place.id);
}
render () {
return (
<MapSidebar
// unable to set ref
/>
)
}
}
and
class MapSidebar extends React.Component {
...
scrollToPlace(id) {
this.refs[id].scrollIntoView({block: 'end', behavior: 'smooth'});
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MapSidebar));
I know that using wrappedComponentRef could get me the contents of withRouter, but then I still have connect to deal with.
I also tried creating a custom ref on the MapSidebar instance:
<MapSidebar
getReference={(ref) => {
this.sidebar = ref;
}} />
and then in the MapSidebar class constructor, calling:
if(this.props.getReference) {
this.props.getReference(this);
}
but that resulted in an infinite loop of that component updating (although I'm not sure I understand why).
Is there a better way to get around these issues?
I suggest you avoid refs and simply pass the scroll value down:
export class Map extends React.Component {
...
handleClick() {
this.setState({scrollToPlaceId: place.id});
}
render () {
return (
<MapSidebar
// Add a new property
scrollToPlace={this.state.scrollToPlaceId}
/>
)
}
}
Then in your sidebar component, just listen to scroll changes in componentWillReceiveProps for example
class MapSidebar extends React.Component {
...
componentWillReceiveProps(nextProps) {
if (nextProps.scrollToPlace !== this.props.scrollToPlace) {
this.refs[nextProps.scrollToPlace].scrollIntoView({block: 'end', behavior: 'smooth'});
}
}
}
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(MapSidebar));
Store a reference in both classes:
// MapSidebar render - add this to the element you want.
<div ref={r => (this.ref = r)}>
Then in Map render:
<MapSidebar ref={r => (this.sidebar = r)}>
Now after Map has mounted you have access to the ref:
this.sidebar.ref

Resources