i want to share props from components to sibling children. I've read about React Context but can't implement it.
My home component looks like this:
const Home = () => {
return (
<>
<Navigation />
<SearchBar />
<Wrapper>
<Filters />
<ProductsList />
</Wrapper>
</>
);
}
I have search state in SearchBar component, and need to pass it to ProductList component
const [search, setSearch] = useState('');
const handleSetSearch = (e) => {
setSearch(e.target.value);
}
return (
<Wrapper>
<StyledTitle>inPal Search</StyledTitle>
<InputWrapper>
<StyledInput type="text" placeholder="Write something..." onChange={(e) => handleSetSearch(e)} />
<SearchIcon src={searchIcon} alt="Search" />
</InputWrapper>
</Wrapper>
);
Can someone help me to understand this?
You can declare the state in parent component (Home) and pass it as prop to both the child components as:
const Home = () => {
const [search, setSearch] = useState('');
return (
<>
<Navigation />
<SearchBar search={search} setSearch={setSearch} />
<Wrapper>
<Filters />
<ProductsList search={search} />
</Wrapper>
</>
);
}
import React, { createContext } from "react";
import ProductsList from "./ProductsList";
const [search, setSearch] = useState('');
const handleSetSearch = (e) => {
setSearch(e.target.value);
}
const Sr = createContext();
return (
<Wrapper>
<StyledTitle>inPal Search</StyledTitle>
<InputWrapper>
<StyledInput type="text" placeholder="Write something..." onChange={(e) => handleSetSearch(e)} />
<SearchIcon src={searchIcon} alt="Search" />
</InputWrapper>
<Sr.Provider value={search}>
<ProductsList/>
</Sr.Provider>
</Wrapper>
);
ProductList
import React, { useContext } from "react";
import { Sr } from "./App";
const ProductList = () => {
const sr = useContext(Sr);
return <h1> your value is here {sr} </h1>
}
Related
This is where i generate the token
import React, { useState, useEffect } from 'react';
import { Paper, Stepper, Step, StepLabel, Typography, CircularProgress, Divider, Button } from '#material-ui/core';
import { commerce } from '../../../lib/commerce';
import useStyles from './styles';
import AddressForm from '../AddressForm';
import PaymentForm from '../PaymentForm';
const steps = ['Shipping address', 'Payment details'];
const Checkout = ({ cart }) => {
const [activeStep, setActiveStep] = useState(0);
const [checkoutToken, setCheckoutToken] = useState(null);
const classes = useStyles();
useEffect(() => {
if (cart.id) {
const generateToken = async () => {
try {
const token = await commerce.checkout.generateToken(cart.id, { type: 'cart' });
setCheckoutToken(token)
} catch (error){
console.log(error);
}
};
generateToken();
}
}, [cart]);
const Confirmation = () => (
<div>
Confirmation
</div>
)
const Form = () => activeStep === 0
? <AddressForm checkoutToken={checkoutToken} />
: <PaymentForm />
return (
<>
<div className={classes.toolbar} />
<main className={classes.layout} >
<Paper className={classes.paper}>
<Typography variant='h4' align='center'>Checkout</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((step) => (
<Step key={step}>
<StepLabel>{step}</StepLabel>
</Step>
))}
</Stepper>
{activeStep === steps.length ? <Confirmation /> : checkoutToken && <Form />}
</Paper>
</main>
</>
)
}
export default Checkout
Here is my App.js
import React, { useState, useEffect, Fragment } from 'react'
import { commerce } from './lib/commerce';
import { Products, Navbar, Cart, Checkout } from './components';
import { BrowserRouter as Router, Routes, Route} from 'react-router-dom';
const App = () => {
const [products, setProducts] = useState([]);
const [cart, setCart] = useState({});
const fetchProducts = async () => {
const { data } = await commerce.products.list();
setProducts(data);
}
const fetchCart = async () => {
setCart(await commerce.cart.retrieve())
}
const handleAddToCart = async ( productId, quantity) =>{
const { cart } = await commerce.cart.add(productId, quantity);
setCart(cart);
}
const handleUpdateCartQty = async (productId, quantity) => {
const { cart } = await commerce.cart.update(productId, { quantity });
setCart(cart);
}
const handleRemoveFromCart = async (productId) => {
const { cart } = await commerce.cart.remove(productId);
setCart(cart);
}
const handleEmptyCart = async () => {
const { cart } = await commerce.cart.empty();
setCart(cart);
}
useEffect(() => {
fetchProducts();
fetchCart();
}, []);
return (
<Router>
<div>
<Navbar totalItems={cart.total_items} />
<Routes>
<Route exact path='/' element={<Products products={products} onAddToCart={handleAddToCart} />} />
<Route exact path='/cart' element={<Cart cart={cart} handleUpdateCartQty={handleUpdateCartQty} handleAddToCart={handleAddToCart} handleRemoveFromCart={handleRemoveFromCart} handleEmptyCart={handleEmptyCart} />} />
<Route exact path='/checkout' element={ <Checkout cart={cart} />} />
</Routes>
</div>
</Router>
)
}
export default App;
And here is my cart.jsx incase their is anything relevant there
import React from 'react'
import { Container, Typography, Button, Grid} from '#material-ui/core';
import { Link } from 'react-router-dom';
import useStyles from './styles';
import CartItem from './CartItem/CartItem';
const Cart = ({ cart, handleUpdateCartQty, handleRemoveFromCart, handleEmptyCart }) => {
const classes = useStyles();
const EmptyCart = () => (
<Typography variant='subtitle1'>
You have no items in your shopping cart.
<Link to='/' className={classes.link}>Add Items!</Link>
</Typography>
);
const FilledCart = () => (
<>
<Grid container spacing={3}>
{ cart.line_items.map((item) => (
<Grid item xs={12} sm={4} key={item.id}>
<CartItem item={item} onUpdateCartQty={handleUpdateCartQty} onRemoveFromCart={handleRemoveFromCart} />
</Grid>
))}
</Grid>
<div className={classes.cardDetails}>
<Typography variant='h4'>
Subtotal: {cart.subtotal.formatted_with_symbol}
<div>
<Button className={classes.emptyButton} size='large' type='button' variant='contained' color='secondary' onClick={handleEmptyCart}>
Empty Cart
</Button>
<Button component={Link} to='/checkout' className={classes.checkoutButton} size='large' type='button' variant='contained' color='primary'>
Checkout
</Button>
</div>
</Typography>
</div>
</>
);
// Wait for cart to load items
if(!cart.line_items){
return '...loading';
}
return (
<Container>
<div className={classes.toolbar} />
<Typography className={classes.title} varaint='h3' gutterBottom >Your Shopping Cart</Typography>
{ !cart.line_items.length ? <EmptyCart /> : <FilledCart />}
</Container>
)
}
export default Cart
[error messages][1]
[1]: https://i.stack.imgur.com/vlard.png
Warning: Expected onSubmit listener to be a function, instead got a
value of string type. form
FormProvider#http://localhost:3000/static/js/bundle.js:76722:7
AddressForm#http://localhost:3000/static/js/bundle.js:1096:7 Form div
Paper#http://localhost:3000/static/js/bundle.js:12332:17
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 main
Checkout#http://localhost:3000/static/js/bundle.js:1332:7
Routes#http://localhost:3000/static/js/bundle.js:67209:7 div
Router#http://localhost:3000/static/js/bundle.js:67146:7
BrowserRouter#http://localhost:3000/static/js/bundle.js:65952:7
App#http://localhost:3000/static/js/bundle.js:347:82
Warning: A component is changing a controlled input to be
uncontrolled. This is likely caused by the value changing from a
defined to undefined, which should not happen. Decide between using a
controlled or uncontrolled input element for the lifetime of the
component. More info: https://reactjs.org/link/controlled-components
input SelectInput#http://localhost:3000/static/js/bundle.js:13482:19
div InputBase#http://localhost:3000/static/js/bundle.js:8257:25
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25
Input#http://localhost:3000/static/js/bundle.js:9146:26
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25
Select#http://localhost:3000/static/js/bundle.js:13182:26
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 div
Grid#http://localhost:3000/static/js/bundle.js:7352:29
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 div
Grid#http://localhost:3000/static/js/bundle.js:7352:29
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 form
FormProvider#http://localhost:3000/static/js/bundle.js:76722:7
AddressForm#http://localhost:3000/static/js/bundle.js:1096:7 Form div
Paper#http://localhost:3000/static/js/bundle.js:12332:17
WithStyles#http://localhost:3000/static/js/bundle.js:19639:25 main
Checkout#http://localhost:3000/static/js/bundle.js:1332:7
Routes#http://localhost:3000/static/js/bundle.js:67209:7
I have this serch.js file. When I search and click on the li in the search result, I want to get redirected to <InnerDetail /> but the URL doesn't change or I don't get redirected to this page
but manualy if I type in the URL localhost/detiled/8 I am redirected to to <InnerDetail /> with id as 8
import React from "react";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import { faSearch } from "#fortawesome/free-solid-svg-icons";
import { useState, useEffect } from "react";
import axios from "axios";
import { Link } from "react-router-dom";
import { useHistory } from "react-router-dom";
const initialState = {
idaddProducts: "",
};
const Searchclients = () => {
const history = useHistory();
const [showResults, setShowResults] = React.useState(true);
const [poName, pnName] = React.useState(initialState);
const [showSerch, setShowSerch] = React.useState([]);
const [detail, setDetail] = useState(false);
const [inputValue, setInputValue] = React.useState("");
const [filteredSuggestions, setFilteredSuggestions] = React.useState([]);
const [selectedSuggestion, setSelectedSuggestion] = React.useState(0);
const [displaySuggestions, setDisplaySuggestions] = React.useState(false);
const suggestions = [];
showSerch.forEach(function (data) {
suggestions.push(data);
});
const onChange = (event) => {
const value = event.target.value;
setInputValue(value);
setShowResults(false);
const filteredSuggestions = suggestions.filter(
(suggestion) =>
suggestion.firstname
.toString()
.toLowerCase()
.includes(value.toLowerCase()) ||
suggestion.id.toString().toLowerCase().includes(value.toLowerCase())
);
setFilteredSuggestions(filteredSuggestions);
setDisplaySuggestions(true);
};
const onSelectSuggestion = (index) => {
setSelectedSuggestion(index);
setInputValue(filteredSuggestions[index]);
setFilteredSuggestions([]);
setDisplaySuggestions(false);
};
const SuggestionsList = (props) => {
// console.log(props);
const {
suggestions,
inputValue,
onSelectSuggestion,
displaySuggestions,
selectedSuggestion,
} = props;
if (inputValue && displaySuggestions) {
if (suggestions.length > 0) {
return (
<ul className="suggestions-list" style={styles.ulstyle}>
{suggestions.map((suggestion, index) => {
// console.log(suggestions);
const isSelected = selectedSuggestion === index;
const classname = `suggestion ${isSelected ? "selected" : ""}`;
return (
<Link to={`/detiled/${suggestion.id}`}> //this link dont work
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
);
})}
</ul>
);
} else {
return <div>No suggestions available...</div>;
}
}
return <></>;
};
useEffect(() => {
axios
.get("all-doctors-list/")
.then((res) => {
const data = res.data;
// pnName(data.data);
// var stringdata = data;
setShowSerch(data);
//console.log(stringdata);
});
// setShowSerch(data);
}, []);
return (
<>
<div className="note-container" style={styles.card}>
<div style={styles.inner}>
<p style={{ textAlign: "left" }}>Search Doctors</p>
<form className="search-form" style={{}}>
{showResults ? (
<FontAwesomeIcon
style={{ marginRight: "-23px" }}
icon={faSearch}
/>
) : null}
<input
onChange={onChange}
value={inputValue}
style={styles.input}
type="Search"
/>
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
</form>
</div>
</div>
</>
);
};
export default Searchclients;
Navigator.js
import React from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import InnerDetail from "./client/doctor/components/innerto_detail.js";
class Navigator extends React.Component {
render() {
return (
<Router>
<div>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/detiled/:id">
<InnerDetail />
</Route>
</Switch>
</div>
</Router>
);
}
}
function Home() {
return (
<div style={{ paddingTop: "20%", textAlign: "center" }}>
<h1>Home</h1>
</div>
);
}
export default Navigator;
when i hover on the<li> the bottom of the browser the path is showing currectly
i think the problem is here i tried another links here nothing is working here
<Link to={`/detiled/${suggestion.id}`}> //this link dont work
<li
style={styles.listyle}
// onMouseOver={{ background: "yellow" }}
key={index}
className={classname}
>
{suggestion.firstname}
</li>
</Link>
i tryed another link under the flowing code
a button called hello and that works i think the probelm is with the return
<SuggestionsList
inputValue={inputValue}
selectedSuggestion={selectedSuggestion}
onSelectSuggestion={onSelectSuggestion}
displaySuggestions={displaySuggestions}
suggestions={filteredSuggestions}
/>
<Link
to={{
pathname: `/detiled/5`,
}}
>
<button>hello</button>
</Link>
try using
<Route path="/detiled/:id" component={InnerDetail} />
instead of
<Route path="/detiled/:id">
<InnerDetail />`
in Navigator.js
and
Route exact path="/">
<Home />
did you created any Home component, and not imported that in Navigator.js
<Link to={"/detiled/"+ suggestion.id}><li>...</li></Link>
this worked for me
I'm new to React and I'm trying to incorporate viewSwitching from https://devexpress.github.io/devextreme-reactive/react/scheduler/docs/guides/view-switching/ into my project. The issue I'm facing is that this view has class components and I've written my code in functional components, is there any way to implement the code given below into functional components so that viewSwitching may work?
import * as React from 'react';
import Paper from '#material-ui/core/Paper';
import { ViewState } from '#devexpress/dx-react-scheduler';
import {
Scheduler,
WeekView,
Appointments,
Toolbar,
ViewSwitcher,
MonthView,
DayView,
} from '#devexpress/dx-react-scheduler-material-ui';
import { appointments } from '../../../demo-data/month-appointments';
export default class Demo extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
data: appointments,
currentViewName: 'work-week',
};
this.currentViewNameChange = (currentViewName) => {
this.setState({ currentViewName });
};
}
render() {
const { data, currentViewName } = this.state;
return (
<Paper>
<Scheduler
data={data}
height={660}
>
<ViewState
defaultCurrentDate="2018-07-25"
currentViewName={currentViewName}
onCurrentViewNameChange={this.currentViewNameChange}
/>
<WeekView
startDayHour={10}
endDayHour={19}
/>
<WeekView
name="work-week"
displayName="Work Week"
excludedDays={[0, 6]}
startDayHour={9}
endDayHour={19}
/>
<MonthView />
<DayView />
<Toolbar />
<ViewSwitcher />
<Appointments />
</Scheduler>
</Paper>
);
}
}
Any help at all will be appreciated :)
import * as React from 'react';
import Paper from '#material-ui/core/Paper';
import { ViewState } from '#devexpress/dx-react-scheduler';
import {
Scheduler,
WeekView,
Appointments,
Toolbar,
ViewSwitcher,
MonthView,
DayView,
} from '#devexpress/dx-react-scheduler-material-ui';
import { appointments } from '../../../demo-data/month-appointments';
const Demo = () => {
const [state, setState] = useState({
data: appointments,
currentViewName: 'work-week'
})
const currentViewNameChange = (currentViewName) => {
setState({ currentViewName });
};
return (
<Paper>
<Scheduler
data={state.data}
height={660}
>
<ViewState
defaultCurrentDate="2018-07-25"
currentViewName={state.currentViewName}
onCurrentViewNameChange={currentViewNameChange}
/>
<WeekView
startDayHour={10}
endDayHour={19}
/>
<WeekView
name="work-week"
displayName="Work Week"
excludedDays={[0, 6]}
startDayHour={9}
endDayHour={19}
/>
<MonthView />
<DayView />
<Toolbar />
<ViewSwitcher />
<Appointments />
</Scheduler>
</Paper>
);
}
export default Demo;
Just update state and function like this
const Demo = (props) => {
const [data, useData] = useState(appointments);
const [currentViewName, setCurrentViewName] = useState("work-week");
const currentViewNameChange = (currentViewName) => {
setCurrentViewName(currentViewName);
};
return (
<Paper>
<Scheduler data={data} height={660}>
<ViewState
defaultCurrentDate="2018-07-25"
currentViewName={currentViewName}
onCurrentViewNameChange={currentViewNameChange}
/>
<WeekView startDayHour={10} endDayHour={19} />
<WeekView
name="work-week"
displayName="Work Week"
excludedDays={[0, 6]}
startDayHour={9}
endDayHour={19}
/>
<MonthView />
<DayView />
<Toolbar />
<ViewSwitcher />
<Appointments />
</Scheduler>
</Paper>
);
};
Here's my app component that renders an input for user to type in. What I want to achieve is that whatever input that the user writes in will be passed down to the Films component. That text is then will be used as a query param to get data from an api endpoint
import React, { useState } from "react";
import Films from "../Films";
import { BrowserRouter as Router, Route } from "react-router-dom";
import "./style.css";
const App = () => {
const [text, setText] = useState("");
const [redirect, setRedirect] = useState(false);
const onSubmit = (event) => {
setRedirect(true);
};
return (
<Router>
<div>
<p className="films-analysis-service">Films Analysis Service </p>
<form id="input-form" onSubmit={onSubmit}>
<input
type="text"
id="input-box"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button className="button" type="submit">
Search
</button>
</form>
{redirect && (
<Route
exact
path="/films"
render={(props) => <Films text={text} />}
/>
)}
</div>
</Router>
);
};
export default App;
This is my Films component:
import React, { useEffect, useState } from "react";
import "./style.css";
const axios = require("axios");
const Films = ({ text }) => {
const [movies, setMovies] = useState([]);
const fetchMoviesByDirectorName = () => {
let config = {
headers: { Authorization: apiKey },
params: {
directorName: text, //the text that is passed down from App component
},
};
axios.get(filmsEndpointURL, config);
};
useEffect(() => {
fetchMoviesByDirectorName();
}, [movies]);
return (
...
);
};
export default Films;
At the moment I'm just trying to print out the data that I would get back but unfortunately I don't think my input value is passed down properly. I don't think my usage of Route is correct.. and it's not redirecting to /films component. What changes should I do to my App.js?
Make sure to do event.preventDefault() in onSubmit
const onSubmit = (event) => {
event.preventDefault(); //<----- like this
setRedirect(true);
};
You can use Redirect to navigate to Films not Route.
Refactored code (using Redirect)
<Router>
<div>
<p className="films-analysis-service">Films Analysis Service </p>
<form id="input-form" onSubmit={onSubmit}>
<input
type="text"
id="input-box"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button className="button" type="submit">
Search
</button>
</form>
<Route exact path="/films" render={(props) => <Films text={text} {...props}/>} /> //<----see here
{redirect && <Redirect to="/films" />} //<----see here
</div>
<Route></Route>
</Router>;
You can also use history object to navigate to Films
import { createBrowserHistory } from "history";
const customHistory = createBrowserHistory();
const App = () => {
const [text, setText] = useState("");
const [redirect, setRedirect] = useState(false);
const onSubmit = (event) => {
// setRedirect(true);//<----no need
customHistory.push("/films");
};
return (
<Router history={customHistory}>
<div>
<p className="films-analysis-service">Films Analysis Service </p>
<form id="input-form" onSubmit={onSubmit}>
<input
type="text"
id="input-box"
value={text}
onChange={(e) => setText(e.target.value)}
/>
<button className="button" type="submit">
Search
</button>
</form>
<Route exact path="/films" render={(props) => <Films text={text} />} />
</div>
</Router>
);
};
export default App;
I have a component called admin it is a form that will redirect me to another page rendering not working though.
Router main
const globalState = {
isAuthed: false,
token: null,
};
export const AuthContext = React.createContext(globalState);
function App() {
const [currentUser, setCurrentUser] = useState(globalState)
return (
<AuthContext.Provider value={[currentUser, setCurrentUser]}>
<Router>
<Switch>
<Route exact path="/admin" component={Admin} />
<Route exact path="/admin-panel" component={Pannel} />
</Switch>
</Router>
</AuthContext.Provider>
)
}
export default App;
admin component
const LoginForm = () => {
const [state, setState] = useContext(AuthContext)
const login = (state) => {
const user = document.getElementById('user').value;
const pass = document.getElementById('pass').value;
const request = {
user,
pass
}
console.log(request)
fetch('/api/admin', {
method: "post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(request),
})
.then(res => res.json())
.then(res => {
if(res.auth){
valid(5000,"Login Success. Redirecting in 3 second")
setTimeout(() =>{
setState({isAuthed: res.auth, token: res.key})
}, 3000)
}
else{
warn(5000,res.message)
}
})
}
return(
<div style={css}>
<ToastContainer />
{(state && state.isAuthed)? <Redirect to='/adming-panel'/>: false}
<h1 style={{color: "teal"}}>Admin Panel</h1>
<Form id="login-form" size='large' style={{backgroundColor: "white"}}>
<Segment stacked>
<Form.Input id="user" fluid icon='user' iconPosition='left' placeholder='E-mail address' />
<Form.Input
fluid
icon='lock'
iconPosition='left'
placeholder='Password'
type='password'
id="pass"
/>
<Button onClick={() => login(state)} color='teal' fluid size='large'>
Login
</Button>
</Segment>
</Form>
</div>
)
}
export default LoginForm
the new page that I want to render
const Pannel = () => {
const [state, setState] = useContext(AuthContext)
return (
<div>
{(!state || !state.isAuthed)? <Redirect to='/adming-panel'/>: false}
Secret Page
</div>
)
}
export default Pannel
All the answers that I searched for. Was to put the exact keyword before the path but still, the component won't render only an empty white screen appears and no errors on console or backend console.
<Route exact path="/admin-panel" component={Pannel} />
Spot the key difference
<Redirect to='/adming-panel'/>
You are welcome.