React Hook to find user - javascript

I am trying to use the React useState Hook for an online project. What I want to happen is, when I type the users name in the search box, It will find the users card on the browser. I am able to log the user to the console, but I am stuck on how to get it to render on screen. Tried so many ways and just not getting it.
console output
App.js
import React, { useState } from 'react';
import CardList from './CardList';
import {robots} from './robots';
import SearchBox from './SearchBox';
function App() {
let [searchInput] = useState('');
function onSearchChange(e) {
searchInput = e.target.value;
const filteredRobots = robots.filter(function(robot){
return robot.name.toLowerCase().includes(searchInput.toLowerCase());
});
console.log(filteredRobots);
}
return (
<div className='tc'>
<h1>RoboFriends</h1>
<SearchBox searchChange={onSearchChange} />
<CardList id={robots.id} name={robots.name} email={robots.email}/>
</div>
);
}
export default App;
CardList.js
import React from 'react';
import Card from './Card';
import {robots} from './robots';
function CardList(props) {
return (
<div>
{
robots.map(function(user) {
return <Card key={user.id} id={user.id} name={user.name} email={user.email} />
})
};
</div> )
}
export default CardList;
Card.js
import React from 'react';
import 'tachyons';
function Card(props) {
return (
<div className='bg-light-green dib br3 pa3 ma2 grow shadow-5'>
<img src={`https://robohash.org/${props.id}`} alt="Robot" />
<h2>{props.name}</h2>
<p>{props.email}</p>
</div>
);
}
export default Card;

React only re-render when you set a state to a new value.
Check the code below:
import React, { useState } from 'react';
import CardList from './CardList';
import {robots} from './robots';
import SearchBox from './SearchBox';
function App() {
let [searchInput, setSeachInput] = useState('');
function onSearchChange(e) {
// set state here to re-render
setSeachInput(e.target.value);
}
// use might want to use useMemo to improve this, I just want to make it simple now
const filteredRobots = robots.filter(function(robot){
return robot.name.toLowerCase().includes(searchInput.toLowerCase());
});
console.log(filteredRobots);
return (
<div className='tc'>
<h1>RoboFriends</h1>
<SearchBox searchChange={onSearchChange} />
{/* using filteredRobots herer*/}
<CardList id={filteredRobots.id} name={filteredRobots.name} email={filteredRobots.email}/>
</div>
);
}
export default App;

In your App.js file, the searchInput is not being set to the state
import React, { useState } from 'react';
import CardList from './CardList';
import {robots} from './robots';
import SearchBox from './SearchBox';
function App() {
let [searchInput, setSearchInput] = useState('');
function onSearchChange(e) {
setSearchInput(e.target.value)
}
**You can pass the filterRobots in place of robots to get only words passed in the search box**
const filteredRobots = robots.filter(function(robot){
return robot.name.toLowerCase().includes(searchInput.toLowerCase());
});
return (
<div className='tc'>
<h1>RoboFriends</h1>
<SearchBox searchChange={onSearchChange} />
<CardList robots={filteredRobots}/>
</div>
);
}
export default App;
In the CardList File
import React from 'react';
import Card from './Card';
function CardList({robots}) {
{
robots.map((user, i) => {
return (
<Card
key={i}
id={user[i].id}
name={user[i].name}
email={user[i].email}
/>
);
})
}
}
export default CardList;

You should not be mutating the searchInput value like searchInput = e.target.value. It is better to call a setter function to update the value. For example,
const [searchInput, setSearchInput] = useState('');
// to update the value of searchInput call setSearchInput
function onSearchChange(e) {
setSearchInput(e.target.value)
}
State changes are asynchronous. When you try to filter the robots it is not guaranteed that it will be called with the latest value of searchInput that's why you should be using useEffect hook which will filter the robots when the value of searchInput changes.
Here is a solution,
import React, { useState } from 'react';
import CardList from './CardList';
import {robots} from './robots';
import SearchBox from './SearchBox';
function App() {
let [searchInput, setSearchInput] = useState('');
let [filterdRobots, setFilteredRobots] = useState(robots);
function onSearchChange(e) {
setSearchInput(e.target.value);
}
useEffect(() => {
setFilteredRobots(robots.filter(r =>
r.name.toLowerCase().includes(searchInput.toLowerCase())))
}, [searchInput, robots])
return (
<div className='tc'>
<h1>RoboFriends</h1>
<SearchBox searchChange={onSearchChange} />
<CardList robots={filteredRobots}/>
</div>
);
}
export default App;
check the codesanbox for demo

Related

ReactJS Context API not passing the data

I am trying to use Context API to create a Trello Clone application. Currently the ElementContext.js does not pass any data to App.js or HomePage.jsx.
I have tried multiple different methods but all result in not finding the data or saying "... is not defined" or just simply not working. My code is listed below.
App.js:
import React, { useContext } from 'react';
import './App.css';
import Todobox from './components/Todobox';
import HomePage from './components/HomePage'
import { ElementContext } from './ElementContext';
function App() {
return (
<>
<ElementContext.Provider>
<HomePage />
</ElementContext.Provider>
</>
);
}
export default App;
ElementContext.js:
import React, { createContext, useState } from 'react';
import Todobox from './components/Todobox';
export const ElementContext = createContext();
export const ElementContextProvider = () => {
const [elements, setElements] = useState([]);
const newElement = () =>{
setElements('Todobox');
};
const value = {
elements,
setElements,
newElement
};
return(
<ElementContext.Provider value={value}> </ElementContext.Provider>
)
}
export default ElementContext;
HomePage.jsx:
import react from 'react';
import { useContext } from 'react';
import '../App.css';
import ElementContext from '../ElementContext';
export default function HomePage(){
const newElement = useContext(ElementContext);
return(
<div className='page-container'>
<div className='header'>
<a className='header-title'>Trello Clone!</a>
<a className='header-button' onClick={newElement}>Create a list</a>
</div>
<div className='element-field'>
</div>
</div>
)
}
Any help is appreciated since I am new! Thank you in advanced! :)
App.jsx
import React, { useContext } from 'react';
import './App.css';
import Todobox from './components/Todobox';
import HomePage from './components/HomePage'
import { ElementContextProvider } from './ElementContext';
function App() {
return (
<>
<ElementContextProvider> // NOT <ElementContext.Provider>
<HomePage />
</ElementContextProvider>
</>
);
}
export default App;
ElementContext.jsx
import React, { createContext, useState } from 'react';
import Todobox from './components/Todobox';
export const ElementContext = createContext();
export const ElementContextProvider = ({children}) => {
const [elements, setElements] = useState([]);
const newElement = () =>{
setElements('Todobox');
};
const value = {
elements,
setElements,
newElement
};
return(
<ElementContext.Provider value={value}>
{children} // PASS CHILDREN COMPONENT
</ElementContext.Provider>
)
}
// export default ElementContext; // REMOVE THIS LINE
Edited HomePage.jsx
import react from 'react';
import { useContext } from 'react';
import '../App.css';
import ElementContext from '../ElementContext';
export default function HomePage(){
const { newElement } = useContext(ElementContext); // NOT const newElement = useContext(ElementContext);
return(
<div className='page-container'>
<div className='header'>
<a className='header-title'>Trello Clone!</a>
<a className='header-button' onClick={newElement}>Create a list</a>
</div>
<div className='element-field'>
</div>
</div>
)
}
Hope this is helpful for you.

How to get data from multiple child component in ReactJS

I was having a parent component named Cart.jsx in react and the child component named Card.jsx.
The Parent component looks like this.
Cart.jsx
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState([]);
return (
<div className="cart__Items">
<Card item={cart[0]} />;
<Card item={cart[1]} />;
<Card item={cart[2]} />;
</div>
)
}
export default Cart;
And the Card Component looks as follows
Card.jsx
import React, { useState } from "react";
function Card() {
const [price,setPrice] = useState(0);
// in-between implemented some function to calculate price value.
return (
<div>
// rendering code
</div>
)
}
export default Card;
Now the problem is, how do I get the price data of each child component and store them in the total array of the parent component.
Here the parent has 3 Cardcomponents, I need to get the price data from each component and store them in the Cart component
Here is the code. I hope this might help
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState(0);
return (
<div className="cart__Items">
{cart.map(crt =><Card item={crt} total={total} setTotal={setTotal} />}
</div>
)
}
export default Cart;
import React, { useState } from "react";
function Card(props) {
const [price,setPrice] = useState(0);
const {setTotal, total} = props
useEffect(()=>{
setTotal(total+price)
},[])
// in-between implemented some function to calculate price value.
return (
<div>
// rendering code
</div>
)
}
export default Card;
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState([]);
return (
<div className="cart__Items">
{cart.map((item) => (<Card item={item} setTotal={setTotal} />))}
</div>
)
}
export default Cart;```
Now you have access to the setTotal function inside each card Item from which you can update the parent state of "total".
If you feel like the individual prices are to be calculated by the child you should use an event handler prop :
Cart.jsx
import React, { useState, useEffect, useContext } from "react";
import Card from "../../Components/Card";
function Cart() {
const cart = [**Array of Objects**]
const [total,setTotal] = useState(0);
const handlePriceCalculated = price => {
setTotal(total + price);
}
return (
<div className="cart__Items">
<Card item={cart[0]} onPriceCalculated={handlePriceCalculated} />
<Card item={cart[1]} onPriceCalculated={handlePriceCalculated} />
<Card item={cart[2]} onPriceCalculated={handlePriceCalculated} />
</div>
)
}
export default Cart;
Card.jsx
import React, { useState } from "react";
function Card({
onPriceCalculated
}) {
const [price,setPrice] = useState(0);
// in-between implemented some function to calculate price value.
...
setPrice(calculatedValue)
onPriceCalculated(calculatedValue)
...
return (
<div>
// rendering code
</div>
)
}
export default Card;
Giving the responsability to the child to set the total is a bad practise and will result in your components not to be reusable as they would be too hardly coupled.

Simple state managment with contextAPI in NextJS

I want to set up a simple global state so that the site owner can update some numeric values whenever he wants to. I created a Provider, added it into custom _app.js and into his admin.js where he can change the value via input and into aboutme.js in which the value should get displayed at the end.
Here is my StateProvider.js:
import React, { useContext, createContext, useState } from 'react';
export const AppContext = createContext();
export const StateProvider = ({ children }) => {
const [dvds, setDvds] = useState(Number);
let sharedState = {
dvds,
setDvds,
};
return (
<AppContext.Provider value={sharedState}>{children}</AppContext.Provider>
);
};
export function useAppContext() {
return useContext(AppContext);
}
which I imported into _app.js:
import '../styles/globals.scss';
import { StateProvider } from '../lib/appCtx';
function MyApp({ Component, pageProps }) {
return (
<>
<StateProvider>
<Component {...pageProps} />
</StateProvider>
</>
);
}
}
export default MyApp;
Here is the admin.js to set the value:
import React, { useEffect, useState, useContext, createContext } from 'react';
import styles from '../styles/Admin.module.scss';
import { AppContext } from '../lib/appCtx';
export default function Admin() {
const { dvds, setDvds } = useContext(AppContext);
const updateState = () => createContext(AppContext);
return (
<>
...
<div className={styles.card}>
<div className={styles.title}>Number of DVDs</div>
<p className={styles.text}>
{new Intl.NumberFormat('de-DE', {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(dvds)}
</p>
<input
type='text'
onChange={(e) => setDvds(e.target.value)}
onKeyPress={updateState}
/>
</div>
</div>
...
</>
);
}
and last but not least the aboutme.js to display the value from context:
import Image from 'next/image';
import styles from '../styles/Aboutme.module.scss';
import { AppContext, useAppContext } from '../lib/appCtx';
export default function AboutMe() {
function thousands_separators(num) {
var num_parts = num.toString().split('.');
num_parts[0] = num_parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
return num_parts.join('.');
}
const dvds = AppContext.dvs;
return (
<div>
...
<div className={styles.col}>
<p>
<span>
{new Intl.NumberFormat('de-DE', {
minimumFractionDigits: 0,
maximumFractionDigits: 0,
}).format(useAppContext(dvds))}
</span>
<br /> dvds in collection
</p>
</div>
</div>
...
);
}
So I want to pass the typed number from admin.js over the Provider into the aboutme.js.
Would anyone be so nice to explain me why it doesn`t work and helping me by providing the right source? Thank you guys!!

React Context api, I can't get to object from context

I started to learn React, I'm trying to retrieve data from api, the data is an object with the fields of base, date & rates, without any problem I can print and logout base & date but rates which is an object not.
console.log gives undefined, when trying to iterate is obviously that the object does not exist but in DevTools i can see normal data
Thank you for your help and greetings
Context:
export const ExchangeProvider = props => {
const [lastestExchanges, setLastestExchanges] = useState({})
const fetchLastestExchange = async () => {
try {
await fetch(`https://api.exchangeratesapi.io/latest`).then(data => data.json()).then(data => setLastestExchanges(data))
} catch (err) {
console.log(err)
}
}
useEffect(() => {
fetchLastestExchange()
}, [])
return (
<ExchangeContext.Provider value={[lastestExchanges, setLastestExchanges]}>
{props.children}
</ExchangeContext.Provider>
)
}
Usage:
import React, {useState, useContext} from "react";
import {ExchangeContext} from "../ExchangeContext";
function HomeView() {
const [lastestExchange, setLastestExchange] = useContext(ExchangeContext)
console.log(lastestExchange)
return (
<div className="container">
<p>{lastestExchange.base}</p>
<p>{lastestExchange.date}</p>
{/*<p>{lastestExchange.rates['PLN']}</p>*/}
<ul>
{/*{Object.keys(lastestExchange.rates).map(key => <li>{lastestExchange.rates[key]}</li>)}*/}
</ul>
</div>
)
}
export default HomeView
Provider usage:
import React from 'react';
import HomeView from "./Views/HomeView";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
import {ExchangeProvider} from "./ExchangeContext";
function App() {
return (
<ExchangeProvider>
<div className="App container w-full flex h-full">
<Router>
<Switch>
<Route path="/">
<HomeView/>
</Route>
</Switch>
</Router>
</div>
</ExchangeProvider>
);
}
export default App;
You can use react context simpler like this :
// src/ThemeContext.js
import React from 'react';
const ThemeContext = React.createContext(null);
export default ThemeContext;
// src/ComponentA.js
import React from 'react';
import ThemeContext from './ThemeContext';
const A = () => (
<ThemeContext.Provider value="green">
<D />
</ThemeContext.Provider>
);
// src/ComponentD.js
import React from 'react';
import ThemeContext from './ThemeContext';
const D = () => (
<ThemeContext.Consumer>
{value => (
<p style={{ color: value }}>
Hello World
</p>
)}
</ThemeContext.Consumer>
);

React Props for Handle Change not a Function

I'm getting props.handleChange is not a function when running the following code. I'm trying to update the state when the checkbox is clicked. The field that is check box is called myNetwork. I thought that when NetworkArray component, which is a parent of Card component, would have access to the functions and state in App? But this is my first React App. Please, what am I doing wrong?
App.JS
import React, {Component} from 'react';
import SignUp from './components/SignUp';
import NetworkArray from './components/NetworkArray';
import {network} from './NetworkData'
import './App.css';
import 'tachyons';
class App extends Component {
constructor() {
super()
this.state = {
network: network,
}
this.handleChange=this.handleChange.bind(this);
}
handleChange(id) {
this.setState(prevState => {
const updatedNetwork = prevState.network.map(netw => {
if (netw.id===id) {
netw.myNetwork = !netw.myNetwork
}
return netw
})
return {
network:updatedNetwork
}
})
}
render() {
return (
<div>
<NetworkArray
network={network}
handleChange = {this.handleChange} />
</div>
);
}
}
export default App;
Card.js
import React from 'react';
const Card = (props) => {
return(
<div className = 'bg-light-green dib br3 pa3 ma2 grow shadow-5'>
<div>
<h3>{props.name}</h3>
<p>{props.company}</p>
<p>{props.phone}</p>
<p>{props.email}</p>
<p>{props.city}</p>
</div>
<div>
MyNetwork
<input
type = "checkbox"
checked={props.myNetwork}
onChange={()=> props.handleChange(props.id)}
/>
</div>
</div>
)
}
export default Card;
NetworkArray.js
import React, {Component} from 'react';
import Card from './Card';
const NetworkArray = ({network}) => {
const cardComponent = network.map((user,i) => {
return(
<Card
key = {network[i].id}
name = {network[i].firstName + ' ' + network[i].lastName}
company = {network[i].company}
phone= {network[i].phone}
email={network[i].email}
city = {network[i].city}
/>
)
})
return (
<div>
{cardComponent}
</div>
)
}
export default NetworkArray;
You passed the function from App component to NetworkArray component, but not to Card component.
const NetworkArray = ({network, handleChange}) => {
...
<Card
handleChange={handleChange}
...
/>
}

Categories