How can I search Giphy's GIF live with React.js? - reactjs

Based on the official Giphy demo(CodeSandBox), I would like to create a live search function for Giphy GIFs.
And below is a demo of it.
search demo(CodeSandBox)
It holds the keyword as state and passes the keyword state to the search method of giphyFetch.
But the search results are not displayed.
Is there a problem with the code in the demo, or a solution to this problem?
Thank you.
source code
const giphyFetch = new GiphyFetch("sXpGFDGZs0Dv1mmNFvYaGUvYwKX0PWIh");
function App() {
const [keyword, setKeyword] = useState("");
const fetchGifs = (offset: number) =>
giphyFetch.search(keyword, { offset, limit: 10 });
return (
<>
<p>
<img src="./logo.gif" width="200" alt="Powered by GIPHY" />
</p>
<p>
input keyword
<input type="text" onChange={e => setKeyword(e.target.value)} />
</p>
<h4>search result</h4>
<Carousel fetchGifs={fetchGifs} gifHeight={200} gutter={6} />
</>
);
}

The Carousal does the fetchGifs once upon mount. So you need to force re-mount upon your input onChange. You can do this by adding dynamic key
Like this
...
<>
<p>
<img src="./logo.gif" width="200" alt="Powered by GIPHY" />
</p>
<p>
input keyword
<input
value={keyword}
type="text"
onChange={e => setKeyword(e.target.value)}
/>
</p>
<h4>search result</h4>
<Carousel
key={keyword}
fetchGifs={() => fetchGifs(5)}
gifHeight={200}
gutter={6}
/>
</>
...
Working demo is here

Related

clear <input> tag value when opening new page from search bar

So I have 2 components. SearchBar.js and ProductDetail.js
The searchBar JS help me to search product from my header. And when clicked it will redirect to another productDetail page. the problem is I got that take a number as the value, when I change it's number and then proceed to search another product. When I got redirected to that productPage, the input value will stay and not reset. How to fix this ?
Here's my code :
ProductDetail.js
const [productCount, setproductCount] = useState(0);
<input
type="number"
className='input-quantity'
value={productCount || 1}
onChange={(e) => {
setproductCount(parseInt(e.target.value))
}}
/>
SearchBar.js
<div className="searchInput">
<input
id="searchKeyInputId"
type="text"
placeholder={placeholder}
onChange={handleFilter}
ref={inputRef}
/>
<BiSearch className="input-append-icon" />
{filteredData.length !== 0 && (
<div className="searchResult">
{filteredData && filteredData.slice(0, 5).map((value) => {
return <Link
to={`/p/${value.id}/${value.slug}`}
className="searchItem"
key={value.id}
onClick={clearInput}
>
<p className='fontRegular'>{value.name}</p>
</Link>
})}
</div>
)}
</div>

Input field not cleared after using useState with onClick

I have a React app, where I'm using an input field as a searchbar, which upon typing, returns a list of products, and upon clicking any product takes you to that product page. I want to clear the typed text in the searchbar after the redirection to new page has happened but I haven't been able to achieve this yet.
I've tried many methods and went over similar posts, but I don't know what am I doing wrong as text is never cleared.
I'm using Material UI for rendering the list and have imported everything as needed.
Below is my code:
Navbar component (contains searchbar)
const Navbar = () => {
const [text, setText] = useState('');
const [liopen, setLiopen] = useState(true);
const getText = (text) => {
setText(text);
setLiopen(false);
};
const handleClick2 = (e) => {
setText('');
setLiopen(true)
};
return (
<header>
<nav>
<div className="middle">
<div className="nav_searchbar">
<span className="search_icon">
<SearchIcon id="search" />
</span>
<input
type="text"
onChange={(e) => getText(e.target.value)}
name=""
placeholder="Search for products, categories, ..."
id=""
/>
</div>
{text && (
<List className="extrasearch" hidden={liopen}>
{products
.filter((product) =>
product.title.toLowerCase().includes(text.toLowerCase())
)
.map((product) => (
<ListItem>
<NavLink
to={`/getproductsone/${product.id}`}
onClick={(e) => {handleClick2(e)}}
>
{product.title}
</NavLink>
</ListItem>
))}
</List>
)}
</nav>
</div>
</header>
);
};
export default Navbar;
You need to set the value of the input if you want it controlled by the component state.
<input value={text}
type="text"
onChange={(e) => getText(e.target.value)}
name=""
placeholder="Search for products, categories, ..."
id=""
/>

Show hide multiple password in react js

I'm currently learning React js. My code work when it has one show hide password. But when i have more than one, i have struggle. This code work, because it has just one.
export default function App() {
const [changePassword, setChangePassword] = useState(true);
const changeIcon = changePassword === true ? false : true;
return (
<div className="wrapper-login">
<div className="wrapper-form">
<h2>Welcome Back!</h2>
<form>
<label>Email</label>
<div>
<input
type="email"
name="email"
required
/>
</div>
<label>Password</label>
<div className="form-group">
<input
type={changePassword ? "password" : "text"}
name="password"
required
/>
<span className="icon"
onClick={() => {
setChangePassword(changeIcon);
}}
>
{changeIcon ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</span>
</div>
</form>
</div>
</div>
);
}
In codesandbox i have 3 input type password, and each input have show hide password. Can you help me to achieved that ? and explain to me why thats work ? . I'm sorry for my bad English. Thank you
You may create a component that controls hide or show behavior. For example, you can create a generic component for isolated show hide behavior. You pass the input name, and it creates a sub-component for you.
export default function ShowHidePassword({ name }) {
const [isVisible, setVisible] = useState(false);
const toggle = () => {
setVisible(!isVisible);
};
return (
<div className="form-group">
<input type={!isVisible ? "password" : "text"} name={name} required />
<span className="icon" onClick={toggle}>
{isVisible ? <EyeOutlined /> : <EyeInvisibleOutlined />}
</span>
</div>
);
}
usage:
<div>
<ShowHidePassword name="name" />
<ShowHidePassword name="password" />
</div>
when you use one state for more than one thing, state changes will effect on all of elements that use the state.
best way is create a reusable input component and import it anywhere and As much as you want. on this way every changes will happen just inside that component and wont effect on others component
dont forget to pass ...props to your input if you want access to the input onChange,name and ....
export const PasswordInput = (props) => {
const [hide, setHide] = useState(false);
const toggle = () => {
setHide((prev) => !prev);
};
return (
<div>
<input type={!isVisible ? "password" : "text"} {...props} required />
<i className="icon" onClick={toggle}>
{hide ? <EyeVisible /> : <EyeInvisible />}
</i>
</div>
);
}
usage:
<div>
<PasswordInput />
<PasswordInput />
<PasswordInput />
</div>
now every toggle will only effect on the clicked input and there is no side effect and re render

How To render properly a component in react useEffect and firebase

I am trying to get instantly data from my Firebase with onSnapshot and it is working.
But the input field got the same amount of data in the Firebase as [object object],[object object] if I have two data in the Firestore. If I want to add data then when I click on the input field, the page becomes white.
I can't add new data this way.
Any help, please?
codesandbox.io ==> https://codesandbox.io/s/long-bush-sjkjnq?file=/src/Body/AppBody.jsx
function AppBody() {
const [reservation, setReservation] = useState([]);
useEffect(()=>{
db.collection('reservations')
.orderBy('timestamp', 'asc')
.onSnapshot(snapshot =>(
setReservation(snapshot.docs.map(doc =>({
id: doc.id,
data: doc.data()
})))
))
},[])
const handleClick = ()=>{
if(!reservation){
return;
}
db.collection('reservations').add({
title: reservation,
timestamp: firebase.firestore.FieldValue.serverTimestamp(),
})
setReservation("");
}
return (
<div className="appBody" >
<div className="appBody__left">
<h3>Reservations: </h3>
<div className="reservationCard">
{reservation.map(({id, data: {title}}) =>{
return <ReservationCardItem
key={id}
id={id}
title={title}
Icon={CloseIcon} />
})}
</div>
<div className="reservationInput">
<input type="text" placeholder="reservation name" value={reservation}
onChange={(e)=>setReservation(e.target.value)} />
<button onClick={handleClick} >Add</button>
</div>
</div>
<div className="vertical__line"></div>
<div className="appBody__right">
<h3>Menus: </h3>
<div className="menu__card">
<div className="menuCard__person">
<h4>Selena gomez</h4>
<CloseIcon />
</div>
<div className="menucard__menu">
<ReservationCardItem title="Selena" Icon={CloseIcon} />
<ReservationCardItem title="Selena" Icon={CloseIcon} />
</div>
<div className="menuCard__input">
<input type="text" placeholder="add Menu item" />
<button>Add</button>
</div>
</div>
</div>
</div>
)
}
export default AppBody
I created another piece of state (like a copy), so that I didn't use the initial state directly. And it worked.
I don't know if it was the better solution, but it worked fine :)

Update Avatar value from Text feild

I am very new with React.JS as well as new for JS. I have to update avatar value from a text field. This is just a small demo project. My target is as below:
It means that if some one has entered Text in
Nick name
Then Avatar Text must be updated. My render method in App.js as below
return (
<div className="App">
<div style={avatarParentContainer}>
<div style={divStyleAvatar}>
</div>
<span style={avatarContainer}>
{avatar}
</span>
</div>
<div>
<Login/>
</div>
</div>
);
Below is my Avatar
avatar= <Avatar
name={this.setState({avatarname:''})}
size="200"
round={true}
style={avatarClass}
/>;
As in above code i have one separate component as
Login
This Login component have Nick Name field as below:
<TextField
hintText="Enter your Nick name"
floatingLabelText="Nick Name"
onChange = {(event,newValue)=>this.setState({nickname:newValue})}
/>
I know this is silly question for expert person but in my case i am struggling with it. Please help me to get rid this issue.
Move state to your App component. Avatar and Login should be a stateless components. Then you can pass function as a prop to Login, and name from state to Avatar component. Something like this (not tested, because I don't have code of these comopnents ;) ):
const Login = ({ onChange }) => (
<TextField
hintText="Enter your Nick name"
floatingLabelText="Nick Name"
onChange = {(event, newValue) => onChange(newValue)}
/>
);
const Avatar = ({ name }) => (
<Avatar
name={name}
size="200"
round={true}
style={avatarClass}
/>
);
And in App:
return (
<div className="App">
<div style={avatarParentContainer}>
<div style={divStyleAvatar}>
<span style={avatarContainer}>
<Avatar name={this.state.avatarname} />
</span>
</div>
<div>
<Login onChange={avatarname => this.setState({avatarname})} />
</div>
);

Resources