Call function from React component in other component - reactjs

Can you help me?
I have two functional components and I need to use function from first component in second component.
I want to use function "sayHello" in function onClicked, but I don't know how to do it.
import React from 'react';
type Props = {
}
const Component_1: React.FunctionComponent<Props> = () => {
const sayHello = () => {
console.log('----Hello');
}
return (
<div className="">
Component 1
</div>
);
};
export default React.memo(Component_1);
const Component_2: React.FunctionComponent<Props> = () => {
const onClicked = () => {
//How ???
//Component_1.sayHello()
}
return (
<div className="">
<div onClick={onClicked}>
Click me
</div>
<Component_1/>
</div>
);
};

const Component_1 = (props) => {
const sayHello = () => {
console.log("----Hello");
};
props.onClicked(sayHello);
return <div className="">Component 1</div>;
};
const Component_2 = () => {
let sayHello;
const fn = function (sayHelloFromComp1) {
sayHello = sayHelloFromComp1;
};
const onClicked = (e) => {
//How ???
//Component_1.sayHello()
sayHello();
};
return (
<div className="">
<div onClick={onClicked}>Click me</div>
<Component_1 onClicked={fn} />
</div>
);
};
export default Component_2;

Related

react image gallery custom play function

I want create custom play button outside the ImageGallery Carousel and toggle play and pause by accessing play() and pause() methods through refs (NOTE: not renderPlayPauseButton)
import React, { useEffect, useRef } from "react";
import ImageGallery from "react-image-gallery";
import "react-image-gallery/styles/css/image-gallery.css";
const images = [
{
original: "https://picsum.photos/id/1018/1000/600/",
thumbnail: "https://picsum.photos/id/1018/250/150/"
},
{
original: "https://picsum.photos/id/1015/1000/600/",
thumbnail: "https://picsum.photos/id/1015/250/150/"
},
{
original: "https://picsum.photos/id/1019/1000/600/",
thumbnail: "https://picsum.photos/id/1019/250/150/"
}
];
export default function App() {
const playRef = useRef(null);
useEffect(() => {
console.log(playRef);
}, []);
return (
<div className="App">
<button onClick={() => playRef?.current?.pauseOrPlay()}>Play</button>
<ImageGallery
ref={playRef}
items={images}
showThumbnails={false}
showFullscreenButton={false}
showPlayButton={false}
infinite={true}
/>
</div>
);
}
Need help !!
How about this:
Javascript version:
export default function App() {
const playRef = useRef(null);
const [isPlaying, setIsPlaying] = useState(false);
const playOrPause = () => {
setIsPlaying((prev) => {
if (playRef) {
playRef.current[prev ? "pause" : "play"]();
}
return !prev;
});
};
return (
<div className="App">
<ImageGallery ref={playRef} items={images} />
<button onClick={playOrPause}>{isPlaying ? "Pause" : "Play"}</button>
</div>
);
}
Typescript version:
export default function App() {
const playRef = useRef<ImageGallery | null>(null);
const [isPlaying, setIsPlaying] = useState<boolean>(false);
const playOrPause = () => {
setIsPlaying((prev) => {
playRef?.current?.[prev ? "pause" : "play"]();
return !prev;
});
};
return (
<div className="App">
<ImageGallery ref={playRef} items={images} />
<button onClick={playOrPause}>{isPlaying ? "Pause" : "Play"}</button>
</div>
);
}
Here is the example:
Javascript version
Typescript version

How to filter or search for services in another component (React)

NOTE: My Page Card component is working correctly. How can I filter the card page component in the Search component?
I'm new to react, and I don't quite understand how I can accomplish this task.
In the Search component I put it in a fixed way, as I can't filter a component using another.
The Code is summarized for ease.
Card Page
import React, {
useEffect,
useState
} from "react";
import classes from "./boxService.module.css";
import axios from "axios";
function BoxService() {
const [test, SetTest] = useState([]);
useEffect(() => {
axios
.get("http://localhost:8080/api/test")
.then((response) => {
SetTest(response.data);
})
.catch(() => {
console.log("Error!");
});
}, []);
return ({
test.map((test, key) => {
<div className={classes.box}
return (
<Grid item xs = {2} key={key} >
<div className={test.name} < div >
<p className={test.description}</p>
</Grid>
);
})}
);
}
export default BoxService;
Seach Page
import React, {
useState,
useEffect
} from "react";
import axios from "axios";
function Search() {
const [searchTerm, setSearchTerm] = useState("");
const [test, SetTest] = useState([]);
//Chamada API
useEffect(() => {
axios
.get("http://localhost:8080/api/test")
.then((response) => {
SetTest(response.data);
})
.catch(() => {
console.log("Error");
});
}, []);
return (
<div>
<input type = "text"
placeholder = "Search..."
onChange = {
(event) => {
setSearchTerm(event.target.value);
}
}/>
{
test.filter((val) => {
if (searchTerm === "") {
return val;
} else if (
val.nome.toLowerCase().includes(searchTerm.toLowerCase())
) {return val;}
}).map((val, key) => {
return ( <div className = "user"
key = {key} >
<p> {val.name} </p> </div>
);
})
} </div>
);
}
export default Search;
Here is an example of how it should/could look like:
import React from "react";
function SearchBox({ setSearchTerm, searchTerm }) {
const handleFilter = (e) => {
setSearchTerm(e.target.value);
};
return (
<>
filter
<input type="search" onChange={handleFilter} value={searchTerm} />
</>
);
}
export default function App() {
const [searchTerm, setSearchTerm] = React.useState("");
const [filteredResults, setFilteredResults] = React.useState([]);
const [results, setResults] = React.useState([]);
React.useEffect(() => {
const fetchdata = async () => {
const randomList = await fetch(`https://randomuser.me/api/?results=50`);
const data = await randomList.json();
const { results } = data;
setResults(results);
};
fetchdata();
}, []);
React.useEffect(() => {
const filterResults = results.filter((item) =>
item.name.last.toLowerCase().includes(searchTerm.toLowerCase())
);
setFilteredResults(filterResults);
}, [searchTerm, results]);
return (
<div className="App">
<SearchBox setSearchTerm={setSearchTerm} searchTerm={searchTerm} />
<div>
<ul>
{filteredResults.map(({ name }, idx) => {
return (
<li key={idx}>
{name.first} {name.last}
</li>
);
})}
</ul>
</div>
</div>
);
}

Add component to useRef object

How would you add a component inside an useRef object (which is refering to a DOM element)?
const Red = () => {
return <div className="color">Red</div>;
};
const Black = () => {
return <div className="color">Black</div>;
};
const Green = () => {
return <div className="color">Green</div>;
};
const Button = (params) => {
const clickHandler = () => {
let boolA = Math.random() > 0.5;
if (boolA) {
params.containerRef.current.appendChild(<Red />);
} else {
let boolB = Math.random() > 0.5;
if (boolB) {
params.containerRef.current.appendChild(<Black />);
} else {
params.containerRef.current.appendChild(<Green />);
}
}
};
return <button onClick={clickHandler}>Click</button>;
};
export default function App() {
const containerRef = useRef(null);
return (
<div className="App">
<Button containerRef={containerRef} />
<div ref={containerRef} className="color-container">
Color components should be placed here !
</div>
</div>
);
}
params.containerRef.current.appendChild(); -> throws an error. I`ve put it to show what I would like to happen.
Also is what I`m doing an anti-pattern/stupid ? Is there another (smarter) way of achieving the above ?
codesandbox link
edit :
I forgot some important information to add.
Only Button knows and can decide what component will be added.
expecting you want to add multiple colors, something like this would work and don't need the ref:
import { useState } from "react";
import "./styles.css";
const Color = () => {
return <div className="color">Color</div>;
};
const Button = (params) => {
return <button onClick={params.onClick}>Click</button>;
};
export default function App() {
const [colors, setColors] = useState([]);
return (
<div className="App">
<Button onClick={() => setColors((c) => [...c, <Color />])} />
<div className="color-container">
{colors}
</div>
</div>
);
}
It's better to have a state that is changed when the button is clicked.
const [child, setChild] = useState(null);
const clickHandler = () => {
setChild(<Color />);
};
const Button = (params) => {
return <button onClick={params.onClick}>Click</button>;
};
<Button onClick={clickHandler} />
<div className="color-container">
Color components should be placed here !
{child}
</div>
Working sandbox
Edit: Refer to #TheWuif answer if you want multiple Colors to be added upon clicking the button repeatedly
There're several things from your code I think are anti-pattern:
Manipulate the real dom directly instead of via React, which is virtual dom
Render the Color component imperatively instead of declaratively
Here's the code that uses useState (state displayColor) to control whether <Color /> should be displayed
import { useState } from "react";
import "./styles.css";
const Color = () => {
return <div className="color">Color</div>;
};
const Button = (props) => {
return <button onClick={props.clickHandler}>Click</button>;
};
export default function App() {
const [displayColor, setDisplayColor] = useState(false);
const clickHandler = () => {
setDisplayColor(true);
};
return (
<div className="App">
<Button clickHandler={clickHandler} />
<div className="color-container">
Color components should be placed here !{displayColor && <Color />}
</div>
</div>
);
}
Codesandbox

how to replace image when onerror is triggered. react js

How would I redirect the image url when error is occuring? Because this is not working. I need a solution for 2021.
edit: Since I am mapping through an array. How would I define password before the return function?
const dispatch = useDispatch();
const passwordList = useSelector((state) => state.passwordList);
const { loading, error, passwords } = passwordList;
const [imgSrc, setImgSrc] = useState(
"`https://example.com/${password.url}`"
);
const handleError = () =>
setImgSrc("https://upload.wikimedia.org/wikipedia/commons/c/ce/Example_image.png");
<ul >
{passwords.map((password) => (
<div>
<li
key={password.id}
>
<img
src={imgSrc}
onError={handleError}
/>
</li>
</div>
))}
</ul>
Here's an example of what I am trying to do:
https://jsfiddle.net/maccman/2kxxgjk8/3/
Functional component
import { useState } from "react";
const SomeComponent = () => {
const [imgSrc, setImgSrc] = useState(/* original src */);
const handleError = () => setImgSrc("https://upload.wikimedia.org/wikipedia/commons/c/ce/Example_image.png");
return <img src={imgSrc} onError={handleError} />
};
Class component
import { Component } from "react";
class SomeComponent extends Component {
constructor(props) {
super(props);
this.state = { imgSrc: /* original src */};
}
handleError = () => this.setState({
imgSrc: "https://upload.wikimedia.org/wikipedia/commons/c/ce/Example_image.png"
});
render() {
return <img src={imgSrc} onError={handleError} />;
}
}

Debounce input does not read keyboard information

I need DebounceInput to read information from my keyboard, but when I type in Ervin for example, the whole list stays and not just Ervin as it used to work. I don't really know where I went wrong. I know that Debounce is supposed to wait until the user stops typing, but even after waiting a minute nothing changed.
This is my files:
DebounceInput:
import {DebounceInput} from 'react-debounce-input';
type Props ={
onChange:Function;
}
const Debounce:React.FC<Props> = ({onChange}) => {
return(
<DebounceInput
onChange={(e) => onChange(e.target.value)}
debounceTimeout={500}
className="SearchInput"
placeholder="Search by user name..."
/>
)
}
export default Debounce
UsersList:
import {UsersContext} from '../../contexts/Users'
type Props = {
filteredUsers:Array<Person>;
}
type Person = {
name:string;
username:string;
}
const UsersList: React.FC = () => {
const filteredUsers = useContext(UsersContext);
return(
<div className="ListHead">
<ol className="list">
{filteredUsers.map((Person) => (
<li key={Person.name}>
<span>{Person.name}</span>
#{Person.username}
</li>
))}
</ol>
</div>
)}
Users:
import React, {useState, useEffect} from 'react';
import axios from 'axios';
type Users = Person[];
type Person = {
name:string;
username:string;
}
export const UsersContext = React.createContext<Users>([]);
const UsersProvider:React.FC= ({children}) => {
const [users, setUsers] = useState<Person[]>([]);
useEffect(() => {
axios
.get(`https://jsonplaceholder.typicode.com/users`)
.then((response) =>{
setUsers(response.data);
})
.catch((error) => {
console.log(error);
});
},[]);
return (
<UsersContext.Provider value={users}>
{children}
</UsersContext.Provider>
)
}
And Main:
const Main:React.FC= () => {
const [showUser, setShowUser] = useState("");
return (
<div>
<div>
<Header/>
</div>
<UsersProvider>
<UsersList />
<Debounce onChange={setShowUser}/>
</UsersProvider>
</div>
)
}
Your debouncing Input does not do anything except for changing the showUser state. Since your users resides in the UsersProvider . You can pass the value of your showUser as a prop to UsersProvider .
const Main:React.FC= () => {
const [showUser, setShowUser] = useState("");
return (
<div>
<div>
<Header/>
</div>
<UsersProvider searchText={showUser}>
<UsersList />
<Debounce onChange={setShowUser}/>
</UsersProvider>
</div>
)
}
Now inside your UsersProvider you can do the following
type UsersProviderProps = {
children: React.ReactNode;
searchText: string;
}
export const UsersContext = React.createContext<Users>([]);
const UsersProvider:React.FC<UsersProviderProps>= ({children, searchText}) => {
const [users, setUsers] = useState<Person[]>([]);
useEffect(() => {
axios
.get(`https://jsonplaceholder.typicode.com/users`)
.then((response) =>{
setUsers(response.data);
})
.catch((error) => {
console.log(error);
});
},[]);
const filteredUsers = useMemo(() => {
if(searchText.trim().length > 0 && users.length > 0){
return users.filter((person) =>
person.name.toLowerCase().includes(searchText.toLowerCase())
);
} else {
return users;
}
}, [searchText, users])
return (
<UsersContext.Provider value={filteredUsers}>
{children}
</UsersContext.Provider>
)
}

Resources