I have an array of objects and displayed them using map. A '+' button associated with each component. I want to update the count of a specific component on button click. I tried with the following code. However, it is updating the count of all the other components also. What can I do to fix this?
import { useState } from 'react';
import { people } from './Data.js';
function App() {
const[count,setCount]=useState(0)
const updateCount=()=>{
setCount(count+1)
}
return (
<div>
<h4>List of Items</h4>
{
people.map((item)=>{
return (
<div key={item.id}>count:{count}
<button onClick={()=>updateCount}>+</button>
</div>
)
})
}
</div>
);
}
export default App;
You need to manage the state individually. Here's a possible alternative, hope it helps.
import React,{ useState } from 'react';
import { people } from './Data.js';
function PeopleItem(props) {
const[count,setCount]=useState(0)
const updateCount=()=>setCount(count+1)
const {item} = props
return <div>count:{count}
<button onClick={updateCount}>+</button>
</div>
}
export function App() {
return (
<div>
<h4>List of Items</h4>
{
people.map((item)=> <PeopleItem key={item.id} item={item}/>)
}
</div>
);
}
If you want to update count on a single component you need to initialize the useState inside the child component. Extract the map and create a component for the return statement. Consider the following:
import { useState } from 'react';
import { people } from './Data.js';
function ChildComponent(props){
const[count,setCount]=useState(0)
const updateCount=() => {
setCount(prev => prev + 1)
}
return (<div>
count:{count}
<button onClick={()=>updateCount()}>+</button>
</div>)
}
function App() {
return (
<div>
<h4>List of Items</h4>
{
people.map((item)=>{
return (
<ChildComponent key={item.id}/>
)
})
}
</div>
);
}
export default App;
Related
I'm trying to use element variables found in the React documentation here: https://reactjs.org/docs/conditional-rendering.html. I'm not sure why it is not rendering the component I have stored in the Output variable.
Submit:
import './Submit.css'
import React, { useEffect, useState } from "react";
import Output from '../Output/Output'
function Submit(props) {
let output;
const process = () => {
console.log(output)
if(props.src === "x" && props.tgt === "y") {
output = <Output src={props.src} tgt={props.tgt}/>
}
}
return (
<>
<button
disabled={props.src === "Source Chain" || props.tgt === "Target Chain"}
onClick={() => process()} className="submit">Submit
</button>
{output}
</>
);
};
export default Submit;
Output component:
import './Output.css'
import React, { useEffect, useState } from "react";
function Output (props) {
return (
<div className="content">;
<a className="contenttitle">{props.src} to {props.tgt}</a>
<h3 className="contentboxtitle"></h3>
<div className ="liquidassets"> </div>
<h3 className="contentboxtitle"></h3>
<div className ="liquidassets"> </div>
</div>
)
}
export default Output;
Thanks for any help!!
Use a state to control the button and use that state to render or not render your output component
import React, { useState } from "react";
export default function SystemsButtonGroup() {
const [showOutput, setShowOutput] = useState(false);
return (
<div>
<button onClick={() => setShowOutput(!showOutput)} className="submit">
Submit
</button>
{showOutput && <div>Replace this with your output component</div>}
</div>
);
}
I am trying to use useState to conditionally render a div but for the life of me I can not figure out how to do it. I think I am close but I can not see what I am doing wrong, I have entirely misunderstood how to do this. What am I doing wrong? I have written this and it does not work..
import React, { useState } from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faWindowClose } from '#fortawesome/free-solid-svg-icons'
function ElementMenuHeader() {
const [elementMenuOpenClose, setElementMenuOpenClose] = useState(true)
const handleClick = () => setElementMenuOpenClose(false)
return (
<div id="App-Close-Element-Menu-Container"
style={{ display: elementMenuOpenClose ? 'block' : 'none'}}
>
<button id="App-Close-Element-Menu"
onClick={() => handleClick }
>
<FontAwesomeIcon icon={faWindowClose} />
</button>
</div>
);
}
export default ElementMenuHeader
Ideally I would like to be able to set the state of elementMenuOpenClose from other components too, but I will cross this bridge first I think.
You can just use a ternary operator and check a against the state in the operator condition return the div you would like based on the state:
{(elementMenuOpenClose? <div>some tags A </div>: <div>Some tags B </div>)}
You may have a parent component of ElementMenuHeader.
Let's say that is ParentElementMenuHeader.
Inside ParentElementMenuHeader component, you can define like
const ParentElementMenuHeader = () => {
const [elementMenuOpenClose, setElementMenuOpenClose] = useState(true);
...
return (
...
{elementMenuOpenClose && (
<ElementMenuHeader
setElementMenuOpenClose={setElementMenuOpenClose}
...
/>
)}
...
);
}
Inside ElementMenuHeader component,
import React, { useState } from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faWindowClose } from '#fortawesome/free-solid-svg-icons'
function ElementMenuHeader({setElementMenuOpenClose}) {
const handleClick = () => setElementMenuOpenClose(false)
return (
<div id="App-Close-Element-Menu-Container">
<button id="App-Close-Element-Menu" onClick={handleClick}>
<FontAwesomeIcon icon={faWindowClose} />
</button>
</div>
);
}
export default ElementMenuHeader
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'm trying to get hold of ref on children component but it doesn't seem to be working. The same approach works fine with the React class component but not with hooks.
import React, { useState, useRef } from "react";
export default function TestContainer(props) {
const ref = useRef(null);
return (
<div className="test-container" onClick={() => console.log(ref) // this logs null always}>
{React.Children.map(props.children, c =>
React.cloneElement(c, {
ref: n => {
console.log(n);
ref.current = n;
},
className: "test-container"
})
)}
</div>
);
}
export function Test(props) {
return <div className="test" {...props}>
{props.children}
</div>
}
Your component is okay. It is probably because the are no children rendered to that component. I reproduced it with using TestContainer in App and put <h2>Ref</h2> as a child of TestContainer:
(removed the comment of course, since it has been hiding the } )
App.js
import React from "react";
import "./styles.css";
import TestContainer from "./TestContainer";
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<TestContainer>
<h2>Ref</h2>
</TestContainer>
</div>
);
}
TestContainer.js
import React, { useState, useRef } from "react";
export default function TestContainer(props) {
const ref = useRef(null);
return (
<div className="test-container" onClick={() => console.log(ref)}>
{React.Children.map(props.children, c =>
React.cloneElement(c, {
ref: n => {
console.log(n);
ref.current = n;
},
className: "test-container"
})
)}
</div>
);
}
CodeSndbox:
HERE
I am working on a React project, In my project I have four components those are App, Componentc,
Componente, Componentf. Now I am trying to pass an Array from App to Componentf using Context API
I successfuly passed an Array, but the problem is in output the Array is showing like side by
side. but what I am expecting it has to show like Unordered list in html
Please help me to acheive this
This is App.js
import React from 'react';
import Componentc from './Componentc/Componentc';
// import './App.css';
export const UserContext = React.createContext()
const fruits = ['Apple','Orange','Banana','Grapes']
function App() {
return (
<div className="App">
<UserContext.Provider value={fruits}>
<Componentc></Componentc>
</UserContext.Provider>
</div>
);
}
export default App;
This is Componentc
import React from 'react';
import './Componentc.css';
import Componente from '../Componente/Componente';
const Componentc = () => {
return(
<Componente></Componente>
)
}
export default Componentc
This is Componente
import React from 'react';
import './Componente.css';
import Componentf from '../Componentf/Componentf';
const Componente = () => {
return(
<Componentf></Componentf>
)
}
export default Componente
This is Componentf
import React from 'react';
import './Componentf.css';
import { UserContext } from '../App'
const Componentf = () => {
return (
<div>
<UserContext.Consumer>
{
user => {
return <div className='d-block'>{user}</div>
}
}
</UserContext.Consumer>
<h1>Component F</h1>
</div>
)
}
export default Componentf
The value of your context is an array, but you are treating it like an object in the context consumer.
You only need to change return <div className='d-block'>{user}</div> by :
{user => {
return user.map(t => (
<div key={t} className="d-block">
{t}
</div>
));
}}
Although your variables should have meaningful names; I recommend changing the name of the user context and variable to be fruits.
Also, If you are using a recent react version (> 16.8), I also recommend that you use React.useContext API to receive values from context, code become more readable.
const Componentf = () => {
const fruits = React.useContext(FruitContext);
return (
<div>
{fruits.map(fruit => (
<div key={fruit} className="d-block">
{fruit}
</div>
))}
<h1>Component F</h1>
</div>
);
};
Here is a codesandbox demo