I have another file of data.js that i'm calling it in my index.js. I know I will get data if I pass it in useState directly like this below.
const [people, setPeople] = useState(data);
But I want to keep the above state null at the start rather than passing data.
const [people, setPeople] = useState([]);
But rather than accessing data this way I want to directly pass it in my setPeople. Is it possible to do that? Something like this. So that it can be accessed in people and can be iterated.
setPeople([...people,{data}])
Index.js
import React, { useState, useReducer } from 'react';
import Modal from './Modal';
import { data } from '../../../data';
// reducer function
const Index = () => {
const [name,setName]= useState('');
const [modal, showModal] = useState(false);
const [people, setPeople] = useState([]);
const handleSubmit = ((e)=>
{
e.preventDefault();
setPeople([...people,{data}])
})
return (
<div>
<form onSubmit={handleSubmit}>
<input type='text' value={name} onChange={((e)=>setName(e.target.value))} />
<button type='submit'>Add</button>
</form>
{
people.map((person,index)=>{
return(
<div key={index}>
<h2>{person.name}</h2>
</div>
)
})
}
</div>
)
};
export default Index;
data.js
export const data = [
{ id: 1, name: 'john' },
{ id: 2, name: 'peter' },
{ id: 3, name: 'susan' },
{ id: 4, name: 'anna' },
];
You can pass this additional data to setPeople in the same way which you pass current people - use spread syntax.
setPeople([ ...people, ...data ])
Also if you want to depend on current people state you should pass callback which always provide you correct value which sometimes can't not happen if you depend on people.
setPeople(( prevPeople ) => [ ...prevPeople, ...data ])
UPDATE
const Index = () => {
const [name,setName]= useState('');
const [modal, showModal] = useState(false);
const [people, setPeople] = useState([]);
useEffect( () => {
setState(data) // this will be added only once when component mounted
}, [])
const handleSubmit = ((e)=>{
e.preventDefault();
setPeople(( prevPeople ) => [ ...prevPeople, { id: ?, name: "Only one new person" } ])
})
return (
<div>
{ /* your jsx */ }
</div>
)
};
UPDATE 2
const handleSubmit = () => {
const peoplesIds = people.map( p => p.id )
const notIncludedData = data.filter( obj => ! peoplesIds.includes( obj.id ) )
setPeople( prev => [ ...prev, ...notIncludedData, { id: 100, name: "new guy" } ] )
}
You can try this at handleSubmit
setPeople([...people,...data])
Related
If you see below, there is a component named TimeOut() in which I am using the useEffect() to set the timer for the alert.
And then I'm calling <TimeOut/> inside the handleSubmit() function inside if(!name). I get an error where I call <TimeOut/> "expected an assignment or function call and instead saw an expression".
import React, { useState, useEffect } from 'react'
import List from './List'
import Alert from './Alert'
function App() {
const [name, setName]= useState('');
const [list, setList] = useState([]);
const [isEditing, setIsEditing] = useState(false);
const [editID, setEditID] = useState(null);
const [alert, setAlert ] = useState({show: false, msg:'', type:''});
const TimeOut =()=>{
useEffect(() => {
setInterval(() => {
// type in message here
setAlert({show:true, msg:'testing this will be displayed with name', type:''})
}, 2000);
}, []);
return <div></div>;
}
const handleSubmit = (e) => {
e.preventDefault();
if (!name) {
// console.log('testing');
//setAlert({show:true, msg:'Value cannot be empty u idiot', type:''});
<TimeOut/>
} else if (name && isEditing) {
} else {
const newItem = { id: new Date().getTime().toString(), title: name };
setList([...list, newItem]);
setName('');
}
};
const forOnChange = (e) =>{
setName(e.target.value);
}
const showAlert = (show= false, type= '', msg= '')=>{
setAlert({show:show, msg:msg, type:type})
}
const removeAllItems = ()=>{
setAlert({show: true, msg: 'List is empty now', type:''});
setList([]);
}
const removeSpecificItem = (id)=>{
const newList = list.filter((item) => item.id !== id);
setList(newList);
}
return (
<section className="section-center">
<form action="" onSubmit={handleSubmit}>
{alert.show ? <Alert alert={alert} removeAlert={showAlert}/> : null}
<h4>Grocery basket</h4>
<input type="text" placeholder="chickets etc" onChange={(e) => setName(e.target.value)}/>
<button value={name} >{isEditing ? 'Edit' : 'Submit'}</button>
<button className="clear-btn" onClick={removeAllItems}>Clear all items</button>
</form>
{list.length > 0 ? <div className="grocery-container">
<List items={list} removeSpecificItem={removeSpecificItem}/>
</div> : null}
</section>
);
}
export default App
Error
Line 31:7: Expected an assignment or function call and instead saw an expression no-unused-expressions
Line 31:8: 'Timeout' is not defined react/jsx-no-undef
The error is at
try this
const handleSubmit = (e) => {
e.preventDefault();
if (!name) {
// console.log('testing');
// <TimeOut/> remove this, you cant use react components here
setAlert({show:true, msg:'Value cannot be empty u idiot', type:''});
setTimeout(function () {
setAlert({show:false, msg:'Value cannot be empty u idiot', type:''});
}, 2000)
} else if (name && isEditing) {
} else {
const newItem = { id: new Date().getTime().toString(), title: name };
setList([...list, newItem]);
setName('');
}
};
I am making a Shopify app using Shopify Polaris.
I used the ActionList component.
https://polaris.shopify.com/components/actions/action-list
I want to change the state value on the onAction event.
I did like this.
const [searchValue, setSearchValue] = useState('');
const handleAction = (value) => {
setSearchValue(value);
}
const a = ["A","B"];
const searchResultsMarkup = (
<ActionList
items={[
{
content: a[0],
onAction: handleAction(a[0]),
},
{
content: a[1],
onAction: handleAction(a[1]),
},
/>
);
I am a beginner in React.
So maybe a silly question.
but kindly teach me.
Thanks
You are passing it down as a prop, so you will have to change it within the Component.
import React, { useState } from 'react';
export const Parent = () => {
const [searchValue, setSearchValue] = useState('');
const handleAction = value => {
setSearchValue(value);
}
return <ActionList changeSearchVal={handleAction} />
}
export const ActionList = ({ changeSearchVal }) => {
return (
<form>
<input type="text" onChange={e => changeSearchVal(e.target.value)}/>
</form>
)
}
If you want to change the searchValue within ActionList.
import React, { useState } from "react";
import "./styles.css";
import Heading from "../src/components/Heading";
import Info from "./Info";
import Card from "../src/components/Cards";
function createCard(Info) {
return <Card key={Info.id} name={Info.name} />;
}
function App() {
const [search, setSearch] = useState("");
const findperson = Info.filter( personName=> {
return personName.name.toLowerCase().includes(search.toLowerCase);
});
return (
<div>
<Heading />
<input
type="text"
placeholder="Search"
onChange={event => setSearch(event.target.value)}
/>
{findperson.map(createCard)}
</div>
);
}
export default App;
-----------------------------------------------------------------------------------------
Array info.js
const Info = [
{
id: 1,
name: "Rahul"
},
{
id: 2,
name: "Rohan"
},
{
id: 3,
name: "rajesh"
}
];
export default Info;
I am trying to make a search-box that fetches data from an array (info) and then filters the data , However while calling the map function my code is breaking and i am not able to display any data ,
console log for findPerson
You are not calling toLowerCase, instead you are passing the function itself.
const findperson = Info.filter( personName=> {
// return personName.name.toLowerCase().includes(search.toLowerCase);
return personName.name.toLowerCase().includes(search.toLowerCase()); // <-- () missing
});
I have a hard time trying to understand where the issue is because i cant really debug, but here is a working example as demonstration on how i would do it, maybe that helps.
import React, { useState, useMemo } from "react";
const items = [
{
id: 1,
name: "Hamilton"
},
{
id: 2,
name: "Bruce"
}
];
const Item = ({ name, id }) => {
return <div>{name}</div>;
}
export default function App() {
const [search, setSearch] = useState("");
const filteredItems = useMemo(() => {
return items.filter(i => search === "" || i.name.toLowerCase().includes(search.toLowerCase()))
}, [search]);
return (
<div className="App">
<input value={search} onChange={ e => setSearch(e.target.value)} />
{
filteredItems.map(Item)
}
</div>
);
}
I am using a react-select-async-paginate. It's working on form submit. I am facing problem in edit form. When I click on edit button, I am able to show all the values in their tags except the select. I have made a few attempts to show the selected value but no luck.
export function UserDropdown(props) {
const [value, setValue] = useState(null);
const defaultAdditional = {
page: 1
};
const onChange = (e) => {
props.getUserEmail(e)
setValue(e)
}
<AsyncPaginate
additional={defaultAdditional}
defaultValue={props.value}
loadOptions={loadPageOptions}
onChange={ (e) => onChange(e)}
/>
}
import UserDropdown from './userDropdown'
export class User extends Component {
constructor(props) {
super(props);
this.state = {
userEmail: ''
}
}
onUserChange(e) {
this.setState({userEmail: e.value})
}
<UserDropdown getUserEmail = { (email) => this.onUserChange(email)} value={this.state.userEmail} />
}
in loadPageOptions I am using the API's response.
If you want to give a controlled select a default value you need to make sure that value initially is the default value. You can only use defaultValue if the select is uncontrolled meaning that it manages state of value internally:
const OPTIONS = [
{
value: 1,
label: "Audi"
},
{
value: 2,
label: "Mercedes"
},
{
value: 3,
label: "BMW"
}
];
const fakeData = async () => {
await new Promise(resolve => setTimeout(resolve, 1000));
return {
results: OPTIONS,
has_more: false
};
};
const loadOptions = async () => {
const response = await fakeData();
return {
options: response.results,
hasMore: response.has_more
};
};
export default function App() {
// this has to be initialized with the default value
const [value, setValue] = useState({ value: 1, label: "Audi" });
return (
<div className="App">
<AsyncPaginate
value={value}
loadOptions={loadOptions}
onChange={setValue}
/>
</div>
);
}
This could be related to my problem, but I tried using the answer with no luck. It is like my react component start an infinite loop (the app hangs) when setting the hook setShow(!show):
There is a sandbox here were the problem is shown:
https://codesandbox.io/s/collapse-gmqpp
import React, { useState, useEffect } from "react";
const CrawlJobs = () => {
const [mediaList, setMediaList] = useState([]);
const [show, setShow] = useState(false);
useEffect(() => {
const fetchMediaData = async () => {
try {
setMediaList([{ id: 1, name: "Facebook" }, { id: 2, name: "Twitter" }]);
} catch (error) {}
};
fetchMediaData();
}, [mediaList]);
const toggle = () => {
setShow(!show);
};
return (
<div>
{mediaList.map(media => (
<div>
<div onClick={() => toggle()}>Show</div>
{show && <h1>Toggled context</h1>}
</div>
))}
</div>
);
};
export default CrawlJobs;
In this hook, you're updating mediaList and watching for changes on the same too.
useEffect(() => {
const fetchMediaData = async () => {
try {
setMediaList([{ id: 1, name: "Facebook" }, { id: 2, name: "Twitter" }]);
} catch (error) {}
};
fetchMediaData();
}, [mediaList]);
That's the cause of the infinite loop. Please use a callback using useCallback or completely remove the dependency array there.