How to substitute values ​in a component from two arrays? - javascript

I have an array of houses that comes from Firestore, and an array of images of those houses that come from Storage. With the help of map, I go through the array of houses and supply information about it to the component. How do I iterate through an array of images and add them to a component?
const List = ({ selectedHouse }) => {
const [houseTitles, setHouseTitle] = useState([]);
const [houseImages, setHouseImages] = useState([]);
const imageListRef = ref(storage, "images/");
useEffect(() => {
const q = query(collection(db, "map-markers"));
onSnapshot(q, (querySnapshot) => {
setHouseTitle(
querySnapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
);
});
}, []);
useEffect(() => {
listAll(imageListRef).then((response) => {
response.items.forEach((item) => {
getDownloadURL(item).then((url) => {
setHouseImages((prev) => [...prev, url]);
});
});
});
}, []);
return (
<div className="list-container" style={{ width: "50%" }}>
<ListItem title={houseTitles[selectedHouse]?.data?.title} />
{houseTitles
.filter((title, index) => index !== selectedHouse)
.map((title, index) => (
<ListItem key={index} title={title?.data?.title} />
))}
</div>
);
};
const ListItem = (props) => {
return (
<div className="list-item">
<img src={props.url} alt="" />
<h2>{props.title}</h2>
</div>
);
};

I think this is the answer you are looking for:
return (
// ...
{houseTitles
.map((title, idx) => ({title, image: houseImages[idx]}))
.filter((_houseArr, idx) => idx !== selectedHouse)
.map((houseArr, idx) => (
<ListItem key={idx} title={houseArr.title?.data?.title} url={/* YOUR IMAGE SRC HERE, IS IT houseArr.image? */} />
))}
// ...
)

Related

How to change the information when clicking on a marker in React-leaflet?

I have a React-leaflet map on the left side with markers placed on it. On the right side there is a list of point names. I need that when clicking on a certain marker, the name of the point that corresponds to the marker becomes 1st in the list. I take the coordinates of the points and the name of the places from the Firestore. How can I implement this behavior?
App.js:
function App() {
const [selectedHouse, setSelectedHouse] = useState();
return (
<div className="App">
<Header />
<div className="map-content">
<Map onSelect={setSelectedHouse} />
<List selectedHouse={selectedHouse} />
</div>
</div>
);
}
Map.js:
const Map = ({ onSelect }) => {
const [coordinates, setCoordinates] = useState([]);
useEffect(() => {
const q = query(collection(db, "map-markers"));
onSnapshot(q, (querySnapshot) => {
setCoordinates(
querySnapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
);
});
}, []);
return (
<div style={{ width: "100%" }}>
<MapContainer
center={center}
zoom={13}
scrollWheelZoom={false}
style={{ height: "100vh" }}
>
<TileLayer
attribution='© OpenStreetMap contributors'
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{coordinates.map((coord, index) => (
<Marker
key={index}
eventHandlers={{
click: () => {
onSelect(index);
},
}}
position={[parseFloat(coord.data.lat), parseFloat(coord.data.lon)]}
icon={defaultIcon}
/>
))}
</MapContainer>
</div>
);
};
List.js:
const List = ({ selectedHouse }) => {
const [houseTitles, setHouseTitle] = useState([]);
useEffect(() => {
const q = query(collection(db, "map-markers"));
onSnapshot(q, (querySnapshot) => {
setHouseTitle(
querySnapshot.docs.map((doc) => ({
id: doc.id,
data: doc.data(),
}))
);
});
}, []);
return (
<div style={{ width: "50%" }}>
{houseTitles
.filter((title, index) => index !== selectedHouse)
.map((title, index) => (
<ListItem key={index} title={title.data.title} />
))}
</div>
);
};
In your List.js you need to add the selected house before the .map part so that the selected house properly appears:
<div style={{ width: "50%" }}>
{<ListItem title={houseTitles[selectedHouse]} />}
{houseTitles
.filter((title, index) => index !== selectedHouse)
.map((title, index) => (
<ListItem key={index} title={title.data.title} />
))}
</div>

Cannot update a component (`TableComponent`) while rendering a different component (`EditComp`). How can i fix this?

I got an error. react-dom.development.js:86 Warning: Cannot update a component (TableComponent) while rendering a different component (EditComp). To locate the bad setState() call inside EditComp, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
at EditComp (http://localhost:3000/static/js/bundle.js:10830:5).
How can i fix this?
My EditComp component
function EditComp({ id, idItem, Edit, editingText, submitEdits, setIdItem, handleEditing, item, style, classBull}) {
return (
<>
{
id === idItem ?
<Fragment>
<td className={classBull(id)}
><input
className={style}
onChange={Edit}
value={editingText}
type="text" /></td>
<td> <button
onClick={() => submitEdits(item)}
>Edit</button></td>
<td> <img onClick={() => setIdItem(null)} src={cansel} alt="cancel" /></td>
</Fragment>
: <th onDoubleClick={() => handleEditing(id)}>{item.text}</th>
}
</>
)
}
My parent component
function TableComponent({ table, removeItem, setTable }) {
const [editingText, setEditingText] = useState("");
const [idItem, setIdItem] = useState(null);
const [style, setStyle] = useState('null');
const [currentItem, setCurrentItem] = useState(null);
const styleActive = () => {
setStyle('table_data_active');
}
const classBull = (id) => {
if (id === idItem) {
return setStyle('table_data_active');;
} else {
return 'table_item'
}
}
const handleEditing = (id) => {
setIdItem(id);
}
const Edit = (e) => {
setEditingText(e.currentTarget.value);
}
const submitEdits = (item) => {
axios.patch(`http://localhost:3004/item/${item.id}`, { text: editingText })
setIdItem(null);
setEditingText('')
}
return (
<thead>
{
table.map((item, id) => {
return (
<tr
onDragStart={(e) => dragStartHandler(e, item)}
onDragLeave={(e) => dragEndHandler(e)}
onDragEnd={(e) => dragEndHandler(e)}
onDragOver={(e) => dragOVerHandler(e)}
onDrop={(e) => dragHandler(e, item)}
draggable={true}
key={item.id}>
<DataItem
styleActive={styleActive}
table={table}
style={style}
idItem={idItem}
handleEditing={handleEditing}
item={item} id={id} />
<EditComp
classBull={classBull}
style={style}
item={item}
handleEditing={handleEditing}
setIdItem={setIdItem}
submitEdits={submitEdits}
editingText={editingText}
Edit={Edit}
id={id}
idItem={idItem} />
<RemoveItem
id={id}
items={item}
removeItem={removeItem} />
</tr>
)
})
}
</thead>
)
}

How to display images from a JSON URL array in React

I have converted a JSON endpoint into a JavaScript array and I've mapped through it to get the key values I need. 3 out of 4 are text values but the first one is an image and it just displays the URL link. I have tried to map through the same array and display just the images and it works but then I cannot merge the two elements into one div.
The code:
export default function Pokes() {
const [pokemonData, setPokemonData] = React.useState({});
React.useEffect(() => {
fetch(
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json"
)
.then((res) => res.json())
.then((data) => setPokemonData(data.pokemon));
}, []);
const allPokes = pokemonData;
const pokemons = Object.values(allPokes);
const pokesData = pokemons.map(pokemon => `${pokemon.img} ${pokemon.num} ${pokemon.name} ${pokemon.type}`);
let renderedOutput = pokesData.map(item => <div className="infodiv" style={{ flex: 1, flexBasis: "33%" }}> {item} </div>)
return (
<main>
<div>
<div style={{ display: "flex", flexWrap: "wrap" }}>{renderedOutput}</div>
</div>
</main>
);
}
const pokesData = pokemons.map(pokemon => `${pokemon.img} ${pokemon.num} ${pokemon.name} ${pokemon.type}`)
This line of code would return "image url number name", what you actually want is the real image which requires the use of the img HTML tag. Implementing this with your code, it would become:
export default function Pokes() {
const [pokemonData, setPokemonData] = React.useState({});
React.useEffect(() => {
fetch(
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json"
)
.then((res) => res.json())
.then((data) => setPokemonData(data.pokemon));
}, []);
const allPokes = pokemonData;
const pokemons = Object.values(allPokes);
let renderedOutput = pokemons.map(pokemon => <div className="infodiv" style={{ flex: 1, flexBasis: "33%" }}> <img src={pokemon.img} /> {pokemon.num} {pokemon.name} </div>)
// Note the code change above ^^^
return (
<main>
<div>
<div style={{ display: "flex", flexWrap: "wrap" }}>{renderedOutput}</div>
</div>
</main>
);
}
Here is the solution if that is what you are looking after. Here is codesandbox for below code;
import { useState, useEffect, useCallback } from "react";
import axios from "axios";
const URI =
"https://raw.githubusercontent.com/Biuni/PokemonGO-Pokedex/master/pokedex.json";
const App = () => {
const [values, setValues] = useState([]);
const getPokomonGo = useCallback(async () => {
try {
const { data } = await axios.get(URI);
if (data) setValues(data?.pokemon);
} catch (err) {
console.log({ err });
}
}, []);
useEffect(() => {
getPokomonGo();
}, [getPokomonGo]);
return (
<div className="App">
<h1>Pokemon Images</h1>
{values &&
values.map(({ num, name, img }) => (
<img src={img} alt={name} key={num} />
))}
</div>
);
};
export default App;
<img src={{item.img}} alt="Lamp" width="100" height="100">

how can I delete the element in react js

I want to create simple application with react js, which should show the users in the display and then when I click on the delete button, it should delete the following item, however I am having some errors.
import React, { useEffect, useState } from 'react'
const App = () => {
const [users, setUsers] = useState([])
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
setUsers(users);
})
}, [users]);
const deleteMe = () => {
setUsers(prevState => {
return prevState.filter(e => e.name)
})
}
return (
<>
{users.map((user) => {
return (
<>
<div> {user.name}
<button onClick={deleteMe}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
}
export default App
To remove the user, the callback (onClick) must have enough information to identify the user to be removed.
In this example, you have some options:
Remove by name. Only if the user names are unique:
const deleteMe = (userName) => {
setUsers(prevState => {
return prevState.filter(e => e.name !== userName)
})
}
return (
<>
{users.map((user) => {
return (
<>
<div> {user.name}
<button onClick={() => deleteMe(user.name)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
Remove by the element itself. Only if the element isn't repeated in the array (the object itself):
const deleteMe = (user) => {
setUsers(prevState => {
return prevState.filter(e => e !== user)
})
}
return (
<>
{users.map((user) => {
return (
<>
<div> {user.name}
<button onClick={() => deleteMe(user)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
Remove by the array index. Only if the state is an array, usually:
const deleteMe = (userIndex) => {
setUsers(prevState => {
return prevState.filter((e, i) => i !== userIndex)
})
}
return (
<>
{users.map((user, i) => {
return (
<>
<div> {user.name}
<button onClick={() => deleteMe(i)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
</>
)
})}
</>
)
See how a second parameter i was added to the map and filter functions. That is usually ignored, but it may be useful sometimes.
As this method may fail if the array is reordered of an element is added/removed between the render and the callback, I wouldn't recommend it unless there is no other alternative.
Look at the useEffect code. Because you have users as a dependency the effect will pick up any changes to that state. State changes, you make an API call, then update users, the effect gets called again on the next render, you update users in state, users gets updated again... etc.
It sounds like you just need an empty dependency array so that the effect is only called once when the component is rendered.
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/users")
.then((response) => response.json())
.then((users) => {
setUsers(users);
})
}, []);
try this , element get deleted and not refresh
import React, { useEffect, useState } from 'react';
const Example = () => {
const [users, setUsers] = useState([]);
useEffect(() => {
fetchData();
}, []);
const fetchData = async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const data = await response.json();
setUsers(data);
// .then()
// .then(users => {
// setUsers(users);
// });
};
const deleteMe = index => {
setUsers(prevState => {
console.log(prevState);
return prevState.filter((e, i) => i !== index);
});
};
return (
<div>
{users.map((user, i) => {
return (
<div>
{' '}
{user.name}
<button onClick={() => deleteMe(i)}> Delete </button>
{/* <button onClick={}> Update </button> */}
</div>
);
})}
</div>
);
};
export default Example;

Trying to learn React hooks and don't understand why this checkbox behavior is broken?

The component loads with 3 todos. If you check the middle one it should get a line through it. Then if you click the [x] button on it, it goes away, but for some reason the todo below it gets checked.
Anyone see the reason for this?
const Todo = props => {
const markCompleted = (checked, index) => {
const newTodos = [...props.todos];
newTodos[index].isCompleted = checked;
props.setTodos(newTodos);
};
const deleteTodo = index => {
const newTodos = [...props.todos];
newTodos.splice(index, 1);
props.setTodos(newTodos);
};
return (
<div
style={{ textDecoration: props.todo.isCompleted ? 'line-through' : '' }}
className="todo"
>
<input
type="checkbox"
onChange={e => markCompleted(e.target.checked, props.index)}
/>
{props.todo.text}
<button onClick={() => deleteTodo(props.index)}>x</button>
</div>
);
};
const TodoForm = props => {
const [value, setValue] = React.useState('');
const addTodo = e => {
e.preventDefault();
if (!value) return;
const newTodos = [...props.todos, { text: value }];
props.setTodos(newTodos);
setValue('');
};
return (
<form onSubmit={addTodo}>
<input
type="text"
className="input"
value={value}
onChange={e => setValue(e.target.value)}
/>
</form>
);
};
const App = () => {
const [todos, setTodos] = React.useState([
{ text: 'Learn about React', isCompleted: false },
{ text: 'Meet friend for lunch', isCompleted: false },
{ text: 'Build really cool todo app', isCompleted: false }
]);
return (
<div className="app">
<div className="todo-list">
{todos.map((todo, index) => (
<Todo {...{ key: index, todo, index, todos, setTodos }} />
))}
<TodoForm {...{ todos, setTodos }} />
</div>
</div>
);
};
ReactDOM.render(
<App />
, document.querySelector('#react'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>
The previously checked checkbox remains rendered. You should explicitly set its checked status instead, so that it's taken from the props every time, rather than possibly from user input:
checked={props.todo.isCompleted}
You also should use functional methods like filter instead of using mutating methods like splice, and newTodos[index].isCompleted = checked; is mutating the todo object - [...props.todos] only shallow clones the array of objects. Spread the todos around the changed object into the array passed to setTodos instead.
props.setTodos([
...todos.slice(0, index),
{ ...todos[index], isCompleted: checked },
...todos.slice(index + 1),
]);
const Todo = props => {
const markCompleted = (checked, index) => {
const { todos } = props;
props.setTodos([
...todos.slice(0, index),
{ ...todos[index], isCompleted: checked },
...todos.slice(index + 1),
]);
};
const deleteTodo = index => {
props.setTodos(props.todos.filter((todo, i) => i !== index));
};
return (
<div
style={{ textDecoration: props.todo.isCompleted ? 'line-through' : '' }}
className="todo"
>
<input
type="checkbox"
onChange={e => markCompleted(e.target.checked, props.index)}
checked={props.todo.isCompleted}
/>
{props.todo.text}
<button onClick={() => deleteTodo(props.index)}>x</button>
</div>
);
};
const TodoForm = props => {
const [value, setValue] = React.useState('');
const addTodo = e => {
e.preventDefault();
if (!value) return;
const newTodos = [...props.todos, { text: value }];
props.setTodos(newTodos);
setValue('');
};
return (
<form onSubmit={addTodo}>
<input
type="text"
className="input"
value={value}
onChange={e => setValue(e.target.value)}
/>
</form>
);
};
const App = () => {
const [todos, setTodos] = React.useState([
{ text: 'Learn about React', isCompleted: false },
{ text: 'Meet friend for lunch', isCompleted: false },
{ text: 'Build really cool todo app', isCompleted: false }
]);
return (
<div className="app">
<div className="todo-list">
{todos.map((todo, index) => (
<Todo {...{ key: index, todo, index, todos, setTodos }} />
))}
<TodoForm {...{ todos, setTodos }} />
</div>
</div>
);
};
ReactDOM.render(
<App />
, document.querySelector('#react'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="react"></div>

Categories

Resources