I am getting no response from the keydown function here, tried calling it on the div container aswell but still isn't firing.
import React from "react";
import ReactDOM from "react-dom";
export default function App() {
const keydown = () => {
console.log('pressed');
}
return (
<div id="container">
<button onKeyDown={keydown}>
test
</button>
</div>
);
}
Although it may differ for other libs components, for <button /> in React you can:
use onClick for mouse click event
use onKeyPress for keyboard event
Refer:
React document: keyboard-events
Assign an index: React not responding to key down event
import React from "react";
export default function App() {
const keydown = () => {
console.log("pressed");
};
const click = () => {
console.log("clicked");
};
return (
<div id="container">
<button onKeyPress={keydown}>Press</button>
<button onClick={click}>Click</button>
</div>
);
}
Try it online:
Extending from the #keikai answer, the convenient approach would be to focus the Button when the component loads. This can be done easily using a combination of useRef and useEffect hooks.
import React from "react";
const {useRef, useEffect } = React;
export default function App() {
const keydown = () => {
console.log("pressed");
};
const inputRef = useRef(null)
useEffect(() => {
inputRef.current.focus()
}, [])
return (
<div id="container">
<button ref={inputRef} onKeyDown={keydown}>Press</button>
</div>
);
}
Related
I'm creating a simple React App and I've stumbled upon something I can't solve.
I've created a button component which I've exported like any other component.
At the moment, I've imported the Button component in my main part because I need two buttons
The problem is that the labels won't render so i have 2 plain buttons..
The label the button should show is Search
Any fixes?
The Button component
import React from 'react';
import './Button.css';
const Button = ({state = "active"}) => {
return (
<button className={`.btn--${state}`}></button>
);
};
export default Button;
My Main component
import React from 'react';
import './Input.css';
import { useState } from 'react';
import Button from '../Button/Button';
const Input = () => {
const [value, setValue] = useState("");
const SearchButton = (e) => {
e.preventDefault();
console.log("click");
};
const ResetButton = (e) => {
e.preventDefault();
setValue("");
};
return (
<main>
<form className='inputfield'>
<h2 className='input-text'>Zoek een Github user</h2>
<div className='input'>
<input className='search' type='text' placeholder='Typ hier een gebruikersnaam...' value={value} onChange={(e) => setValue(e.target.value)}></input>
<div className='button-field'>
<Button state="inactive" className='search-now' onClick={SearchButton}>Search</Button>
<Button className='reset' onClick={ResetButton}></Button>
</div>
</div>
</form>
</main>
);
};
export default Input;
You have two straight forward ways of this doing what you want.
The first solution would be to use children React Docs Here
Your button then would look like:
const Button = ({state = "active"}) => {
const {children} = props
return (
<button className={`.btn--${state}`}>{children}</button>
);
};
A second approach is to pass the Value through props to the component.
<Button
state="inactive"
className='search-now'
onClick={SearchButton}
textValue={"Search"} />
// Button
const Button = ({state = "active"}) => {
const {textValue} = props
return (
<button className={`.btn--${state}`}>{textValue}</button>
);
};
I am trying to show and hide a functional component, it's works only works on load. after hide it's not shows again. i understand that, the way i use the functional component in wrong way.
any one suggest me the correct way please?
here is my code : (index.tsx)
import React, { Component, useState } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
const App = () => {
const [isBoolean, setBoolean] = useState(false);
const showComponent = () => {
setBoolean(true);
};
return (
<div>
<Hello isBoolean={isBoolean} />
<p>Start editing to see some magic happen :)</p>
<button onClick={showComponent}>Show hello component</button>
</div>
);
};
render(<App />, document.getElementById('root'));
Hello component:
import React, { useEffect, useState } from 'react';
export default ({ isBoolean }: { isBoolean: boolean }) => {
const [isShow, setIsShow] = useState(false);
useEffect(() => {
setIsShow(isBoolean);
}, [isBoolean, setIsShow]);
const shufler = () => {
setIsShow(false);
};
if (!isShow) {
return null;
}
return (
<div>
<p>hi {JSON.stringify(isShow)}</p>
<button onClick={shufler}>Hide Component</button>
</div>
);
};
Live Demo
To explain why your code isn't working:
useEffect(() => {
setIsShow(isBoolean);
}, [isBoolean, setIsShow]);
initially when you set isBoolean to true in parent, this useEffect in child runs too
Then you set isShow to false from the child component
Then again you set isBoolean to true in the parent component, but for the useEffect above, the isBoolean is true now, and it was true also in previous render, so it doesn't run anymore.
So if possible, no need to duplicate isBoolean state also in child, just pass it as props and use it directly, as in the other answer.
No need to maintain a derived state from prop in child component(Hello), you can pass callback and state as props from parent component(index) to child.
Cause of the Problem:
After hiding the component isShow was set to false , isBoolean is still true. So the next time when we click the show button isBoolean hasn't changed, it's still true which will not trigger the useEffect in the Hello.tsx , isShow was never set to true which causes the child to return null.
index.tsx
import React, { Component, useState } from 'react';
import { render } from 'react-dom';
import Hello from './Hello';
import './style.css';
const App = () => {
const [isBoolean, setBoolean] = useState(false);
const showComponent = () => {
setBoolean(true);
};
const hideComponent = () => {
setBoolean(false);
}
return (
<div>
<Hello isBoolean={isBoolean} hideComponent={hideComponent} />
<p>Start editing to see some magic happen :)</p>
<button onClick={showComponent}>Show hello component</button>
</div>
);
};
render(<App />, document.getElementById('root'));
Hello.tsx
import React, { useEffect, useState } from 'react';
export default ({ isBoolean, hideComponent }: { isBoolean: boolean }) => {
if (!isBoolean) {
return null;
}
return (
<div>
<p>hi {JSON.stringify(isBoolean)}</p>
<button onClick={hideComponent}>Hide Component</button>
</div>
);
};
how we can observe if a JSX element mounted or not. for example I have a simple component with useEffect on. it inside of my App.js I can mount and unmount my component and the useEffect inside of that component will log if it is mounted or unmounted.
but I wonder if there is way to that with JSX elements. for example , can we implement that for an h2 tag inside of an App.js without creating component ?
App.js
import React, { useState } from "react";
import "./App.css";
import Mycomponent from "./Mycomponent";
const App = () => {
const [mount, setMount] = useState(true);
return (
<div>
<b>Mounting and Unmounting</b>
<button
onClick={() => {
setMount(!mount);
}}
>
{mount ? "click to unmount" : "click to mount"}
</button>
{mount && <Mycomponent />}
</div>
);
};
export default App;
Mycomponent.js :
import React, { useEffect } from "react";
const Mycomponent = () => {
useEffect(() => {
console.log("mounted");
return () => {
console.log("unmounted");
};
}, []);
return (
<div>
<h1>component mounted</h1>
</div>
);
};
export default Mycomponent;
I think you can use callback refs for that:
export default function App() {
const [counter, setCounter] = React.useState(0);
const measuredRef = (node) => {
if (node == null) {
console.log('I was removed');
} else {
console.log('I was mounted');
}
};
return (
<div
onClick={() => {
setCounter(counter + 1);
}}
>
{counter % 2 == 0 && <h1 ref={measuredRef}>Hello, world</h1>}
<p>Start editing to see some magic happen :)</p>
</div>
);
}
There is a somewhat related example in the docs about that:
In this example, the callback ref will be called only when the
component mounts and unmounts, since the rendered <h1> component stays
present throughout any rerenders.
I'm building a filter Modal in algolia. On that filter Modal, I have a standard refinementlist (see below code). When the user hits "Search" on the modal, the refinementlist values are lost (ie not applied to my component), but there is no guide on how to store refinementlist output.
What I'd like is to essentially have my Refinement list values not to clear when I close my modal.
refinementlist.js
import React from 'react';
import { RefinementList } from 'react-instantsearch-dom';
const toRefine = () => {
return (
<div>
<RefinementList
attribute={`tags`}
searchable
limit={5}
/>
</div>
);
};
export default toRefine;
filter.js
import React from 'react';
import toRefine from './toRefine';
const Filters = () => {
return (
<div>
<toRefine />
</div>
);
};
export default Filters;
MainPage.js
import React, { useState } from 'react';
import Hits from './hits';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch } from 'react-instantsearch-dom';
import Modal from 'react-modal';
import Filters from './filters';
Modal.setAppElement('#root');
const searchC = algoliasearch($ENV_VARS);
const Page = () => {
const [ modalIsOpen, setIsOpen ] = useState(false); //Hook for modal
function openModal() {
setIsOpen(true);
}
function closeModal() {
setIsOpen(false);
}
return (
<div>
<InstantSearch
indexName="index"
searchClient={searchC}
>
<CustomSearchBox />
<button onClick={openModal}>Show FILTERS</button>
<Configure hitsPerPage={20} />
<Hits />
<Modal
isOpen={modalIsOpen}
onRequestClose={closeModal}
contentLabel="filterElement"
className={styles.modal}
overlayClassName={styles.overlay}
>
<FilterPage />
</Modal>
</InstantSearch>
</div>
);
};
export default Page;
Each React InstantSearch widget is responsible for its UI state and needs to be mounted. I'm not familiar with react-modal, but from what I gather reading their documentation, the modal instance is destroyed when closing, not hidden, so the RefinementList is unmounted as well.
What you can do to circumvent this behavior is persist the widget's state manually whenever it changes except when closing the modal, and inject it to the widget as its default refinement.
function App() {
const [brandState, setBrandState] = React.useState([]);
// ...
return (
<InstantSearch
onSearchStateChange={(state) => {
if (modalIsOpen && state.refinementList?.brand) {
setBrandState(state.refinementList.brand);
}
}}
>
<Modal isOpen={modalIsOpen}>
<RefinementList
defaultRefinement={brandState}
attribute="brand"
/>
</Modal>
</InstantSearch>
);
}
You always need to have the RefinementList mounted in the application so that the state is persisted in React InstantSearch's internal state. You can do it declaratively by creating a virtual refinement list, which doesn't render anything, using the connectRefinementList connector.
import { connectRefinementList } from 'react-instantsearch-dom';
// ...
const VirtualRefinementList = connectRefinementList(() => null);
function App() {
// ...
return (
<InstantSearch
onSearchStateChange={(state) => {
if (modalIsOpen && state.refinementList?.brand) {
setBrandState(state.refinementList.brand);
}
}}
>
<VirtualRefinementList defaultRefinement={brandState} attribute="brand" />
{/* ... */}
</InstantSearch>
);
}
You can see it in action in this CodeSandbox demo.
I've got a few React functional Components that I would like to share a state. In this example two toggle buttons that would conditionally show/hide a searchbar and a navbar.
--Solution, based on the accepted answer, on the bottom--
I'm completely new to useContext() and I keep running into the following error in the console:
Uncaught TypeError: setSearchbarToggle is not a function This goes for both buttons.
Bellow I have a filtered example code. It is just for the example I use the states in one file. In real life I would re-use the states in multiple functional components.
This is my header.js
import React, { useState, useContext } from "react"
import "./header.sass"
import { Context } from "./HeaderContext"
export const Header = () => {
const headerContext = useContext(Context)
const { navbarToggle, setNavbarToggle, searchbarToggle, setSearchbarToggle } = headerContext
return (
<React.Fragment>
<div className={"sticky-top"}>
<button onClick={ () => setNavbarToggle( !navbarToggle )}> Toggle Menu </button>
<button onClick={ () => setSearchbarToggle( !searchbarToggle )}> Toggle Search </button>
{navbarToggle && <h3>Menu is showing</h3>}
{searchbarToggle && <h3>Searchbar is showing</h3>}
</div>
</React.Fragment>
)
}
export default Header
And this is my HeaderContext.jsx
import React, { createContext, useState } from "react";
import PropTypes from "prop-types";
export const Context = createContext({});
export const Provider = props => {
const {
navbarToggle: initialNavBarToggle,
searchbarToggle: initialSarchbarToggle,
children
} = props;
const [navbarToggle, setNavbarToggle] = useState(initialNavBarToggle);
const [searchbarToggle, setSearchbarToggle] = useState(initialSarchbarToggle);
const headerContext = {
navbarToggle, setNavbarToggle,
searchbarToggle, setSearchbarToggle
};
return <Context.Provider value={headerContext}>{children}</Context.Provider>;
};
export const { Consumer } = Context;
Provider.propTypes = {
navbarToggle: PropTypes.bool,
searchbarToggle: PropTypes.bool
};
Provider.defaultProps = {
navbarToggle: false,
searchbarToggle: false
};
I hope you can shed some light on this for me
--edit--
This is my code based on the accepted answer.
import React, { useContext } from "react"
import { Provider,Context } from "./HeaderContext"
export const HeaderWithContext= () => {
const headerContext = useContext(Context)
const { navbarToggle, setNavbarToggle, searchbarToggle, setSearchbarToggle } = headerContext
return (
<React.Fragment>
<div className={"sticky-top"}>
<button onClick={ () => setNavbarToggle( !navbarToggle )}> Toggle Menu </button>
<button onClick={ () => setSearchbarToggle( !searchbarToggle )}> Toggle Search </button>
{navbarToggle && <h3>Menu is showing</h3>}
{searchbarToggle && <h3>Searchbar is showing</h3>}
</div>
</React.Fragment>
)
}
export const Header = () => {
return (
<Provider>
<HeaderWithContext/>
</Provider>
)
};
One of the parent components, e.g. App, must wrap the header (or one of its ancestor components) with Context.Provider:
import { Provider } from "./HeaderContext"
...
<Provider>
<Header />
</Provider>