Reacts generate two input feilds dynamically instead of one - reactjs

So this is my app which i have created in react and store data in firestore, i have a form in which ingredients is an array, i can dynamically add the input feilds and when i submit the form it gets submiited and the data gets stored in firebase. My problem is when i click the add feild button instead of one feild two feilds are simultaneously created and i am unable to understand how to do that so if anyone can explain what to do thanks .
code :
function App() {
const [recipes, setRecipes] = useState([])
const [form, setForm] = useState({
ingredients: [],
})
const [popupActive, setPopupActive] = useState(false)
const recipesCollectionRef = collection(db, "recipes")
useEffect(() => {
onSnapshot(recipesCollectionRef, snapshot => {
setRecipes(snapshot.docs.map(doc => {
return {
id: doc.id,
viewing: false,
...doc.data()
}
}))
})
}, [])
const handleView = id => {
const recipesClone = [...recipes]
recipesClone.forEach(recipe => {
if (recipe.id === id) {
recipe.viewing = !recipe.viewing
} else {
recipe.viewing = false
}
})
setRecipes(recipesClone)
}
const handleSubmit = e => {
e.preventDefault()
if (
!form.ingredients ||
) {
alert("Please fill out all fields")
return
}
addDoc(recipesCollectionRef, form)
setForm({
ingredients: [],
})
setPopupActive(false)
}
const handleIngredient = (e, i) => {
const ingredientsClone = [...form.ingredients]
ingredientsClone[i] = e.target.value
setForm({
...form,
ingredients: ingredientsClone
})
}
const handleIngredientCount = () => {
setForm({
...form,
ingredients: [...form.ingredients, ""]
})
{ recipe.viewing && <div>
<h4>Ingredients</h4>
<ul>
{ recipe.ingredients.map((ingredient, i) => (
<li key={i}>{ ingredient }</li>
))}
</ul>

As far as I have understood. Just do like below,
const handleIngredientCount = () => {
setForm({
...form,
ingredients: [...form.ingredients, "", ""],
})
}
You will be created with two input fields simultaneously instead of one when you click the add ingredient button.

Related

get message failed data

I have a page with an order fetch, one can use a select to sort by furthest date or nearest date. On the select everything works, the problem comes from the input where I can enter a command number for the search, it works except that the state does not change on the page when retrieving the state, and if the number command does not exist I am unable to change the state and retrieve the error message. If anyone can look at my code that would be cool. Thanks
part redux
const initialState = {
data:[{
dateCommande: "",
dateDuJour: "",
heureDuJourCommande: "",
horaire: "",
patisseriesList: "",
pays: "",
phone: "",
prixTotal: "",
ville: ""
}],
message:""
}
export default function CommandManagementAdmin(state = initialState,action){
const {type, payload} = action;
switch (type) {
case ActionTypes.GET_ALL_COMMAND_ADMIN:
return {state : payload.data}
case ActionTypes.GET_ALL_COMMAND_ID_CLIENT_ADMIN:
return payload;
case ActionTypes.GET_COMMAND_BY_NUMBER_COMMAND_ADMIN:
return {state: payload};
case ActionTypes.RESULT_COMMAND_NULL_MESSAGE:
return {...state,state:payload[0].message} ;
case ActionTypes.DELETE_COMMAND_BY_ID_ADMIN:
return state === Object.values(state).filter((command) => command.id_commande !== payload)
case ActionTypes.ERROR_GET_ALL_COMMAND_BY_ID_CLIENT_ADMIN:
return { ...state, payload };
default:
return state;
}
}
Service get
export const getCommandByNumberCommandAdminService = (dispatch, numberCommand) =>{
axios.get(BASE_URL + Url_api.API_URL_GET_COMMAND_BY_NUMERO_COMMAND + numberCommand, { headers: ConfigHeaderAdmin()})
.then((response)=>{
const ifCommand = response.data.result
if (ifCommand.length > 0) {
const dataCommand = response.data.result[0]
dispatch(ActionTypes.actionGetCommandByNumberCommandAdmin(dataCommand))
}else{
const message = response.data.message
dispatch(ActionTypes.actionCommandNullMessageAdmin(message))
}
})
.catch((error)=>{
console.log({error: error.message})
})
}
view
const AllCommandComponent = () =>{
const dispatch = useDispatch()
const ifIsCommand = useSelector(state=> state?.reducerCommandAdmin?.state)
const [listCommand, setListCommand ] = useState([])
const [ filterDate, setFilterDate ] = useState("all");
const [ commandByNumber, setCommandByNumber ] = useState("");
useEffect(()=>{
setListCommand(ifIsCommand)
getAllCommandAllClientsAdminService(dispatch)
},[ listCommand, filterDate])
const handleChange = (e) =>{
setFilterDate(e.target.value)
}
const ResultChoiceDateCommand = () =>{
if (filterDate === "oldDay") {
const sortListCommandOld = listCommand?.sort((a, b) => new Date(a.dateDuJour) - new Date(b.dateDuJour))
return setListCommand(sortListCommandOld)
}
if (filterDate === "recentDate") {
const sortListCommandOld = listCommand?.sort((a, b) => new Date(b.dateDuJour) - new Date(a.dateDuJour))
return setListCommand(sortListCommandOld)
}
}
const ListAllCommand = () => {
return listCommand?.map((command, index) => {
return (
<Commands command={command} index={index} />
)
})
}
return(
<div className="esai">
<select className="command_tri_select" onChange={(e)=> handleChange(e)} defaultValue={"all"}>
<option value="all">Toutes les commandes</option>
<option value="oldDay">Commande la plus ancienne</option>
<option value="recentDate">Commande la plus récente</option>
</select>
{ListAllCommand}
<ResultChoiceDateCommand />
</div>
)
}

Convert an array to array map in reactjs firebase

In my app, user can input the timings of his slots and the data will be stored in the firebase, but the data is not being stored as a map. It's being stored like this, can someone tell how to achieve this or share a tutorial.
I want it to be stored as an array map, where people can add multiple slots instead of just one slot, i realise i need it store as an array map but i am not able to create one, something like this :
Code :
const [recipes, setRecipes] = useState([])
const [form, setForm] = useState({
ingredients: [],
const [popupActive, setPopupActive] = useState(false)
const recipesCollectionRef = collection(db, "recipes")
useEffect(() => {
onSnapshot(recipesCollectionRef, snapshot => {
setRecipes(snapshot.docs.map(doc => {
return {
id: doc.id,
viewing: false,
...doc.data()
}
}))
})
}, [])
const handleSubmit = e => {
e.preventDefault()
if (
!form.ingredients ||
!form.steps
) {
alert("Please fill out all fields")
return
}
addDoc(recipesCollectionRef, form)
setForm({
ingredients: [],
steps: []
})
setPopupActive(false)
}
const handleIngredient = (e, i) => {
const ingredientsClone = [...form.ingredients]
ingredientsClone[i] = e.target.value
setForm({
...form,
ingredients: ingredientsClone
})
}
return (
<div className="App">
<h1>My recipes</h1>
<button onClick={() => setPopupActive(!popupActive)}>Add recipe</button>
<div className="recipes">
{ recipes.map((recipe, i) => (
<div className="recipe" key={recipe.id}>
{ recipe.viewing && <div>
<h4>Ingredients</h4>
<ul>
{ recipe.ingredients.map((ingredient, i) => (
<li key={i}>{ ingredient }</li>
))}
</ul>

React - API data only showing if I manually refresh the page

I'm new to React and I created a small admin panel where you can add, edit, remove products. I would like to display 3 products from API when someone opens the app the first time and don't have edited products yet, but this data only shows if I manually refresh the page. I only want to display that if edited product is false, but initially I set edited products to false yet somehow it's not displaying, though I see the data as well as edited is set to false in the console.
Demo
https://react-storeadminpanel.herokuapp.com/
Here is the related code:
const Products = () => {
const {products, setProducts, setAllProducts, allProducts, editedItems, setEditedItems} = useProduct();
useEffect(() => {
async function fetchProducts() {
const res = await axios.get('https://a.nacapi.com/LimeGreen/products/').catch(err => console.log(err));
if(res) {
setProducts(res.data)
setEditedItems(false);
if(allProducts.length === 0 && editedItems === false) setAllProducts(products);
if(allProducts.length === 0 && editedItems === true) setAllProducts(allProducts);
if(allProducts.length > 0) setAllProducts([...allProducts]);
}
return res;
}
fetchProducts();
}, []);
return (
<Wrapper classname="wrapper">
<h1>All Products</h1>
<Cards>
{!!allProducts.length && (
allProducts.map(product => (
<ProductCard name={product.name} description={product.Description} price={product.Price} discount={product.Discount} key={product.uuid}/>
))
)}
</Cards>
</Wrapper>
)
}
The context, where I use LocalStorage
export const ProductContext = React.createContext();
export function useProduct() {
return useContext(ProductContext);
}
export function ProductProvider({children}) {
const [products, setProducts] = useLocalStorage('Api Data', []);
const [addedProduct, setAddedProduct] = useLocalStorage('Added Item', []);
const [allProducts, setAllProducts] = useLocalStorage('All Products', []);
const [editedItems, setEditedItems ] = useLocalStorage('Edited', false);
const [isAdded, setIsAdded] = useState(false);
const value = {
products,
setProducts,
addedProduct,
setAddedProduct,
allProducts,
setAllProducts,
editedItems,
setEditedItems,
isAdded,
setIsAdded,
}
return (
<ProductContext.Provider value={value}>
{children}
</ProductContext.Provider>
)
}
And Code where I set edit products to true
const ProductEdit = () => {
const {allProducts, setAllProducts, setEditedItems} = useProduct();
const [editProductId, setEditProductId] = useState(null);
const [editForm, setEditForm] = useState({
name: "",
Description: "",
Price: "",
Discount: "",
})
const saveEditHandler = (e) => {
e.preventDefault();
const fieldName = e.target.getAttribute("name");
const fieldValue = e.target.value;
const newForm = {...editForm};
newForm[fieldName] = fieldValue;
setEditForm(newForm);
}
const editHandler = (e, product) => {
e.preventDefault();
setEditProductId(product.uuid);
const formValues = {
name: product.Name,
Description: product.Description,
Price: product.Price,
Discount: product.Discount
}
setEditForm(formValues);
}
const submitEditsHandler = (e) => {
e.preventDefault();
const editedProduct = {
name: editForm.Name,
Description: editForm.Description,
Price: editForm.Price,
Discount: editForm.Discount,
uuid: editProductId
}
const newProducts = [...allProducts];
const index = allProducts.findIndex((product) => product.uuid === editProductId);
newProducts[index] = editedProduct;
setAllProducts(newProducts);
setEditedItems(true);
setEditProductId(null);
}
const cancelHandler = () => {
setEditProductId(null);
}
const deleteHandler = (productId) => {
const newProducts = [...allProducts];
const index = allProducts.findIndex((product) => product.uuid === productId);
newProducts.splice(index, 1);
setAllProducts(newProducts);
setEditedItems(true);
};

Set value to textfield with hooks and redux material ui

I'm building an app using react, redux, and redux-saga.
The situation is that I'm getting information from an API. In this case, I'm getting the information about a movie, and I will update this information using a basic form.
What I would like to have in my text fields is the value from the object of the movie that I'm calling form the DB.
This is a brief part of my code:
Im using 'name' as an example.
Parent component:
const MovieForm = (props) => {
const {
movie,
} = props;
const [name, setName] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
onSubmit({
name,
});
};
const handleSetValues = () => {
console.log('hi');
console.log(movie, name);
setName(movie.name);
setValues(true);
};
useEffect(() => {
if (movie && values === false) {
handleSetValues();
}
});
return (
<Container>
<TextField
required
**defaultValue={() => {
console.log(movie, name);
return movie ? movie.name : name;
}}**
label='Movie Title'
onChange={(e) => setName(e.target.value)}
/>
</Container>
);
};
export default MovieForm;
....
child component
const MovieUpdate = (props) => {
const { history } = props;
const { id } = props.match.params;
const dispatch = useDispatch();
const loading = useSelector((state) => _.get(state, 'MovieUpdate.loading'));
const created = useSelector((state) => _.get(state, 'MovieUpdate.created'));
const loadingFetch = useSelector((state) =>
_.get(state, 'MovieById.loading')
);
const movie = useSelector((state) => _.get(state, 'MovieById.results'));
useEffect(() => {
if (loading === false && created === true) {
dispatch({
type: MOVIE_UPDATE_RESET,
});
}
if (loadingFetch === false && movie === null) {
dispatch({
type: MOVIE_GET_BY_ID_STARTED,
payload: id,
});
}
});
const updateMovie = (_movie) => {
const _id = id;
const obj = {
id: _id,
name: _movie.name,
}
console.log(obj);
dispatch({
type: MOVIE_UPDATE_STARTED,
payload: obj,
});
};
return (
<div>
<MovieForm
title='Update a movie'
buttonTitle='update'
movie={movie}
onCancel={() => history.push('/app/movies/list')}
onSubmit={updateMovie}
/>
</div>
);
};
export default MovieUpdate;
Then, the actual problem is that when I use the default prop on the text field the information appears without any problem, but if i use defaultValue it is empty.
Ok, I kind of got the answer, I read somewhere that the defaultValue can't be used int the rendering.
So I cheat in a way, I set the properties multiline and row={1} (according material-ui documentation) and I was able to edit this field an receive a value to display it in the textfield

Can't display elements of array React

I can see my array in state, but I don't know why elements of array doesn't display on the app interface.
const [members, setMembers] = useState([])
useEffect( () => {
getMembers();
}, [props.event])
const getMembers = () => {
let new_members = [];
console.log(props.event)
props.event && props.event.uczestnicy.map(member => {
member.get().then(doc => {
let new_member;
new_member = {
...doc.data(),
id: doc.id
}
new_members.push(new_member)
})
setMembers(new_members)
})
console.log(new_members)
console.log(members)
}
[...]
{members && members.map(member => {
console.log('mem',member)
return(
<div key={member.id}>
{member.nick}
</div>
)
})}
So I can see this array in Components using React Developer Tools, but even console.log doesn't see it in the moment of performing.
And console.log(new_members) and console.log(members) result :
Your member values are fetch asynchronously, so its ideal if you set state only after all the values are resolved. For this you can use a Promise.all
const getMembers = async () => {
let new_members = [];
console.log(props.event)
if(props.event) {
const val = await Promise.all(props.event.uczestnicy.map(member => {
return member.get().then(doc => {
let new_member;
new_member = {
...doc.data(),
id: doc.id
}
return new_member
})
});
setMembers(values);
console.log(values);
}
}

Resources