react-router | Declarative routing for React | Router library
kandi X-RAY | react-router Summary
Support
Quality
Security
License
Reuse
Currently covering the most popular Java, JavaScript and Python libraries. See a Sample Here
react-router Key Features
react-router Examples and Code Snippets
Trending Discussions on react-router
Trending Discussions on react-router
QUESTION
I'm trying to somehow test a hooked file that uses an Apollo client connection entry and GraphQL:
See the error:
Invariant Violation: Could not find "store" in either the context or props of "Connect(withRouter(Apollo(Connect(SearchResults))))". Either wrap the root component in a , or explicitly pass "store" as a prop to "Connect(withRouter(Apollo(Connect(SearchResults))))".
My test file:
A piece of information that I can clarify is that the mock component, in this case I took it from the model that is suggested by react itself.
import React from 'react'
import { mount } from 'enzyme'
import SearchResults from './Searchresults'
import { BrowserRouter as Router } from 'react-router-dom'
import { MockedProvider } from 'react-apollo/test-utils'
import { graphql, compose } from 'react-apollo'
import gql from 'graphql-tag'
import { connect } from 'react-redux'
describe('SearchResults', () => {
const searchBookWithFiltersQuery = gql`query SearchBookWithFiltersQuery(
$searchTerm: String!) {
...
}`
const ComposeComponent = compose(
graphql(searchBookWithFiltersQuery, {
options: ({ match, location }) => ({
variables: {
searchTerm: searchTerm,
opts:prepare_opts(location.search),
page: 1
}
})
}),
connect(mapStateToProps))(SearchResults)
it('should render the given tourTitle', () => {
let mocks = []
const page_filter = mount(
).find(page_filter.tourTitle)
expect(page_filter.text()).toBe(page_filter.tourTitle)
})
})
ANSWER
Answered 2021-Jun-15 at 20:47I finally found the solution to the problem:
import { MockedProvider } from 'react-apollo/test-utils'
import { Router } from 'react-router-dom'
import { searchBookWithFiltersQuery } from 'api/queries'
describe('SearchResults', () => {
const customHistory = createBrowserHistory()
const mockStore = configureMockStore()
const store = mockStore({
user: {
id: 1
}
})
it('should render the given sidebar filter wrapper results', () => {
let mocks = [
{
request: {
query: searchBookWithFiltersQuery
},
result: {
data: {
[{"id":1,
"title":"text 1"
}, {
{"id":2,
"title":"text 2"
}]
}
}
}
}
]
const search = mount(
)
expect(search.containsMatchingElement()).toEqual(
true
)
})
QUESTION
I am building an app following the Rest Countries API challenge from frontendmentor (https://www.frontendmentor.io/challenges/rest-countries-api-with-color-theme-switcher-5cacc469fec04111f7b848ca). I have run into a problem. When clicking on the router link in countryDetail.js, the url changes but the component doesn't get re-rendered unless the page is refreshed.
CountryDetails.js
import React, { useState, useEffect } from "react";
import axios from "axios";
import {Link} from "react-router-dom";
import {CountryDetailStyles, ImgContainer, CountryInfo, CountryInfoDetails, CountryDetailsWrapper, CountryInfoDetailsInner, CountryBorders, LinkWrapper} from "../styles/CountryDetailStyles";
function CountryDetail({match, history}) {
const [item, setItem] = useState([]);
const [allCountries, setAllCountries] = useState([]);
useEffect(() => {
fetchItem();
setBorderCountries();
}, []);
const fetchItem = async () => {
const response = await axios.get(`https://restcountries.eu/rest/v2/name/${match.params.name}?fullText=true`);
setItem(response.data)
}
const setBorderCountries = async () => {
const response = await axios.get(`https://restcountries.eu/rest/v2/all`);
setAllCountries(response.data)
}
// get borders full name using alpha3code
const getBorderCountryName = (allCountries, border) => {
const matchingCountry = allCountries.find(country => {
return country.alpha3Code === border;
})
return matchingCountry.name;
}
return (
Go Back
{
item.length > 0 && item.map(i => (
{i.name}
Native Name: {i.nativeName}
Population: {i.population.toLocaleString()}
Region: {i.region.length > 0 ? i.region : 'N/A'}
Sub Region: {i.subregion.length > 0 ? i.subregion : 'N/A'}
Capital: {i.capital.length > 0 ? i.capital : 'N/A'}
Top Level Domain: {i.topLevelDomain}
Currencies: {i.currencies[0].name}
Languages: {i.languages.map(lang => lang.name).join(", ")}
Border Countries:
{allCountries.length > 0 && i.borders.map(border => {
const borderName = getBorderCountryName(allCountries, border);
return ({borderName})
})}
))
}
)
}
export default CountryDetail;
App.js
import './App.css';
import { ThemeProvider } from 'styled-components';
import { lightTheme, darkTheme } from './styles/themes';
import { GlobalStyles } from './styles/global';
import { useState } from 'react';
import Navbar from './components/Navbar';
import { useDarkMode } from './hooks/useDarkMode';
import CountryList from './components/CountryList';
import CountryDetail from './components/CountryDetail';
import {Route} from "react-router-dom";
function App() {
const [theme, toggleTheme] = useDarkMode();
const themeMode = theme === 'dark' ? darkTheme : lightTheme;
return (
);
}
export default App;
Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
,
document.getElementById('root')
);
reportWebVitals();
ANSWER
Answered 2021-Jun-15 at 17:07The issue seems to be that you are already on the "/country/:name"
path and are clicking to visit another country. The router correctly updates the URL in the address bar, but because CountryDetail
is already mounted it neglects to recompute the item
and allCountries
state. This is because the useEffect
hook only runs once when the component mounts.
The name
param (match.params.name
) is actually a dependency for the GET requests, it should be added to the useEffect
hook's dependency array.
useEffect(() => {
fetchItem();
setBorderCountries();
}, [match.params.name]);
const fetchItem = async () => {
const response = await axios.get(
`https://restcountries.eu/rest/v2/name/${match.params.name}?fullText=true`
);
setItem(response.data);
}
It seems allCountries
doesn't have this dependency, so I recommend splitting it into its own useEffect
hook with empty dependency array so you fetch this data only once when the component mounts.
useEffect(() => {
setBorderCountries();
}, []);
useEffect(() => {
fetchItem();
}, [match.params.name]);
QUESTION
Hi am trying to do a CRUD application am able to do the add user but i got stock with the edit user Actually for my edit user page i just copied the add user page there and then modified it
This is what my app has to do: normally when i enter the edit user page it has to show me the user's existing information then on my part i can now modify it if i wish and then it is stored in my mysql database but it doesn't return anything i actually console logged it to see if it returns anything but it doesn't
index.js
const express = require("express");
const app = express();
const mysql = require('mysql2');
const cors = require('cors');
app.use(cors());
app.use(express.json());
const db = mysql.createConnection({
user: 'root',
host: 'localhost',
password: 'obincharity',
database: 'adherents_system',
port: '3306',
});
app.post('/create', (req, res) => {
const Nom = req.body.Nom
const Email = req.body.Email
const Profession = req.body.Profession
const Date_naiss = req.body.Date_naiss
const Tel = req.body.Tel
const Date_adhession = req.body.Date_adhession
const formData = req.body.formData
db.query('INSERT INTO new_table(Nom,Email,Profession,Date_naiss,Telephone,Date_adhession,Sex) VALUES(?,?,?,?,?,?,?) ',
[Nom, Email, Profession, Date_naiss, Tel, Date_adhession, formData], (err, result) => {
if (err){
console.log(err)
}else{
res.send("Values Inserted")
}
});
})
app.get('/adherents', (req,res) => {
db.query("SELECT * FROM new_table", (err, result) => {
if (err){
console.log(err);
}else{
res.send(result);
}
});
});
app.put('/update',(req,res)=>{
const id = req.body.id
const Nom = req.body.Nom
const Email = req.body.Email
const Profession = req.body.Profession
const Date_naiss = req.body.Date_naiss
const Tel = req.body.Tel
const Date_adhession = req.body.Date_adhession
const formData = req.body.formData
db.query("UPDATE SET new_table Nom=?,Email=?,Profession=?,Date_naiss=?,Telephone=?,Date_adhession=?,Sex=? WHERE id=?",
[Nom, Email, Profession, Date_naiss, Tel, Date_adhession, formData,id], (err, result) => {
if (err){
console.log(err);
}else{
res.send(result);
}
})
} )
app.listen(3005, () =>{
console.log("server working");
});
This is my add user page
import React, { useState} from "react";
import './Inscription.css';
import Axios from 'axios';
function Inscription (){
const [Nom, setNom] = useState("");
const [Email, setEmail] = useState("");
const [Profession, setProfession] = useState("");
const [Date_naiss, setDate_naiss] = useState(0);
const [Tel, setTel] = useState(0);
const [Date_adhession, setDate_adhession] = useState(0);
const [formData, setformData] = useState("")
const addAdherent = () =>{
Axios.post('http://localhost:3005/create',{
Nom: Nom,
Email: Email,
Profession: Profession,
Date_naiss: Date_naiss,
Tel: Tel,
Date_adhession: Date_adhession,
formData:formData,
}).then(()=>{
console.log("success");
})
}
return(
Fiche d'inscription
Nom Utilisateur
{setNom(event.target.value);}}/>
Email
{setEmail(event.target.value);}}/>
Profession
{setProfession(event.target.value);}}/>
Date_naissance
{setDate_naiss(event.target.value);}}/>
Telephone
{setTel(event.target.value);}}/>
Date_adhession
{setDate_adhession (event.target.value);}} />
male
{setformData(event.target.value);}} />
female
{setformData (event.target.value);}} />
)
}
export default Inscription;
And here is my edit user page
import React, { useState, useEffect} from "react";
import {useParams} from 'react-router-dom'
import './Inscription.css';
import Axios from 'axios';
function EditUser () {
const {id} = useParams();
const [Nom, setNom] = useState("");
const [Email, setEmail] = useState("");
const [Profession, setProfession] = useState("");
const [Date_naiss, setDate_naiss] = useState(0);
const [Tel, setTel] = useState(0);
const [Date_adhession, setDate_adhession] = useState(0);
const [formData, setformData] = useState("")
const editUser = () =>{
Axios.post('http://localhost:3005/create',{
Nom: Nom,
Email: Email,
Profession: Profession,
Date_naiss: Date_naiss,
Tel: Tel,
Date_adhession: Date_adhession,
formData:formData,
}).then(()=>{
console.log("success");
})
}
const loadUser = () =>{
Axios.get("http://localhost:3005/adherents/"+ id)
.then((response) => {
console.log(response);
})
}
useEffect(() => {
loadUser();
},[]);
return(
Editer les informations de l'utilisateur
Nom Utilisateur
{setNom(event.target.value);}}/>
Email
{setEmail(event.target.value);}}/>
Profession
{setProfession(event.target.value);}}/>
Date_naissance
{setDate_naiss(event.target.value);}}/>
Telephone
{setTel(event.target.value);}}/>
Date_adhession
{setDate_adhession (event.target.value);}} />
male
{setformData(event.target.value);}} />
female
{setformData (event.target.value);}} />
)
}
export default EditUser;
ANSWER
Answered 2021-Jun-15 at 16:54Get data based on its id (Server Side)
app.get('/adherents/:id', (req, res) => {
db.query(
`SELECT * FROM new_table WHERE id=${req.params.id}`,
(err, result) => {
if (err) {
console.log(err);
} else {
res.json(result);
}
}
);
});
Get data based on its id (Front Side)
const [myData, setMyData] = useState([]);
const {id} = useParams();
const getData = async () => {
try {
const res = await Axios.get(`http://localhost:3005/adherents/${id}`);
await setMyData(res.data);
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getData();
}, []);
Update data (Server Side)
app.put('/update/:id', (req, res) => {
const data = {
Nom: req.body.Nom,
Email: req.body.Email,
Profession: req.body.Profession,
Date_naiss: req.body.Date_naiss,
Tel: req.body.Tel,
Date_adhession: req.body.Date_adhession,
formData: req.body.formData
};
db.query(`UPDATE new_table SET ? WHERE id=${req.params.id}`, data, (err, result) => {
if (err) {
console.log(err);
} else {
res.json(result);
}
});
});
Update data (Front Side)
import React, { useState, useEffect } from 'react';
import Axios from 'axios';
export default function App() {
const {id} = useParams();
const [myData, setMyData] = useState({});
const [Nom, setNom] = useState('');
const [Email, setEmail] = useState('');
const [Profession, setProfession] = useState('');
const [DateNaiss, setDateNaiss] = useState('');
const [Tel, setTel] = useState('');
const [DateAd, setDateAd] = useState('');
const [formData, setFormData] = useState('');
// get function
const getData = () => {
try {
Axios.get(`http://localhost:3005/adherents/${id}`).then((res) => {
setMyData(Object.assign({}, ...res.data)); // array of object to object
});
} catch (error) {
console.log(error);
}
};
// update function
const updateData = async (e) => {
e.preventDefault();
try {
Axios.put(`http://localhost:3005/update/${id}`, {
Nom,
Email,
Profession,
Date_naiss: DateNaiss,
Tel,
Date_adhession: DateAd,
formData,
}).then(() => {
console.log('success');
getData(); // callback to refresh the data display
});
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getData();
}, []);
// myData is an object so we can easily access its content and assign it to states
useEffect(() => {
setNom(myData.Nom);
setEmail(myData.Email);
setProfession(myData.Profession);
setDateNaiss(myData.Date_naiss);
setTel(myData.Tel);
setDateAd(myData.Date_adhession);
setFormData(myData.formData);
}, [myData]);
return (
- {myData.Nom}
- {myData.Email}
- {myData.Profession}
- {myData.Date_naiss}
- {myData.Tel}
- {myData.Date_adhession}
- {myData.formData}
setNom(e.target.value)}
/>
setEmail(e.target.value)}
/>
setProfession(e.target.value)}
/>
setDateNaiss(e.target.value)}
/>
setTel(e.target.value)}
/>
setDateAd(e.target.value)}
/>
setFormData(e.target.value)}
/>
Submit
);
}
QUESTION
package.json
{
"name": "assignment10",
"version": "0.1.0",
"private": true,
"dependencies": {
"@date-io/date-fns": "^2.10.8",
"@material-ui/core": "^4.11.4",
"@material-ui/pickers": "^3.3.10",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
"@types/jest": "^26.0.15",
"@types/node": "^12.0.0",
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"babel-preset-mobx": "^2.0.0",
"chromedriver": "^90.0.0",
"enzyme": "^3.11.0",
"enzyme-adapter-react-16": "^1.15.6",
"enzyme-to-json": "^3.6.2",
"jest": "^26.6.0",
"mobx": "latest",
"mobx-react": "^7.1.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-intl": "^5.17.4",
"react-router-dom": "^5.2.0",
"react-scripts": "4.0.3",
"styled-components": "^5.3.0",
"typescript": "^4.1.2",
"web-vitals": "^1.0.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"lint": "eslint --ext .js,.jsx,.ts,.tsx src --color",
"test": "jest -u",
"browsertest": "nightwatch",
"coverage": "jest --coverage"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/enzyme": "^3.10.8",
"@types/enzyme-adapter-react-16": "^1.0.6",
"@types/react-router-dom": "^5.1.7",
"@types/styled-components": "^5.1.9",
"@typescript-eslint/eslint-plugin": "4.22.1",
"@typescript-eslint/parser": "4.22.1",
"babel-eslint": "10.1.0",
"eslint": "^7.25.0",
"eslint-config-airbnb": "18.2.1",
"eslint-config-airbnb-typescript": "12.3.1",
"eslint-config-prettier": "8.3.0",
"eslint-config-react-app": "6.0.0",
"eslint-import-resolver-typescript": "2.4.0",
"eslint-loader": "4.0.2",
"eslint-plugin-flowtype": "5.7.2",
"eslint-plugin-import": "2.22.1",
"eslint-plugin-jsx-a11y": "6.4.1",
"eslint-plugin-react": "^7.23.2",
"eslint-plugin-react-hooks": "4.2.0",
"nightwatch": "^1.6.4"
}
}
nightwatch.conf.js
module.exports = {
"src_folders" : ["./src/nightWatch"],
"webdriver" : {
"start_process": true,
"server_path": "node_modules/chromedriver/lib/chromedriver/chromedriver",
"port": 9515
},
"test_settings" : {
"default" : {
"desiredCapabilities": {
"browserName": "chrome"
}
}
}
}
when i run the script npm run browsertest i directly get a connection refused from google chrome. I have already deactivated sandboxing in the browser and disabled all proxies. I have also changed ports, but I just can't figure it out.
Does anyone have a solution? I have Debian 10 as OS
ANSWER
Answered 2021-Jun-15 at 14:23Hello I have found a solution. I had several instances running and therefore the npm start then selected a different port than I defined in the test. Have killed all processes on the port and restarted
QUESTION
I am building an app following the Rest Countries API challenge from frontendmentor. I have run into a problem. When trying to find the border countries full name using the alpha3code, I get the error : TypeError: Cannot read property 'name' of undefined
.
import React, { useState, useEffect } from "react";
import axios from "axios";
import {Link} from "react-router-dom";
import {CountryDetailStyles, ImgContainer, CountryInfo, CountryInfoDetails, CountryDetailsWrapper, CountryInfoDetailsInner, CountryBorders, LinkWrapper} from "../styles/CountryDetailStyles";
function CountryDetail({match}) {
useEffect(() => {
fetchItem();
}, []);
useEffect(() => {
setBorderCountries();
}, []);
const [item, setItem] = useState([]);
const [allCountries, setAllCountries] = useState([]);
const fetchItem = async () => {
const response = await axios.get(`https://restcountries.eu/rest/v2/name/${match.params.name}?fullText=true`);
setItem(response.data)
}
const setBorderCountries = async () => {
const response = await axios.get(`https://restcountries.eu/rest/v2/all`);
setAllCountries(response.data)
}
// get borders full name using alpha3code
const getBorderCountryName = (allCountries, border) => {
const matchingCountry = allCountries.find(country => {
return country.alpha3Code === border;
})
return matchingCountry.name;
}
return (
Go Back
{item.map(i => (
{i.name}
Native Name: {i.nativeName}
Population: {i.population.toLocaleString()}
Region: {i.region}
Sub Region: {i.subregion}
Capital: {i.capital}
Top Level Domain: {i.topLevelDomain}
Currencies: {i.currencies[0].name}
Languages: {i.languages.map(lang => lang.name).join(", ")}
Border Countries:
{i.borders.map(border =>{
const borderName = getBorderCountryName(allCountries, border);
return ({borderName})
})}
))}
)
}
export default CountryDetail;
ANSWER
Answered 2021-Jun-15 at 10:55This may not answering your question but have you tried console.log(response.data) before setItem(response.data) to check the data you get from axios.get? sometimes console.log can help
QUESTION
I'm creating 2 pages (Summary and Cycles pages) using react.js
.
On the Summary page, there is a column named CN
that every item links to the Cycles page.
Summary page has a path /route/summary/location=abc
and Cycles page has a path /route/cycle/location=abc/deviceId=4410
For example, if I click the value from CN
column in the first row of the table inside the Summary page, I will be redirected to the Cycles page with the path /route/cycle/location=abc/deviceId=4410
.
In the Summary page, I use https://github.com/react-bootstrap-table/react-bootstrap-table2 for the table component and I use a columnRenderer
function inside columns.js
to render a custom item inside the table like this one:
How can I put the pathname
(example "abc") to a Link component inside cnColumnRenderer
function in columns.js
?
Summary page with the path: /route/summary/location=abc
Cycles page with the path: /route/cycle/location=abc/deviceId=4410
Error because of invalid hook call while rendering the Summary page
My Code:table code inside Summary page (inside Summary.js):
hint: focus on columns
variable from './columns' and its implementation
import React from "react"
import { useLocation } from "react-router-dom"
import BootstrapTable from 'react-bootstrap-table-next';
import paginationFactory, {
PaginationProvider,
PaginationListStandalone
} from 'react-bootstrap-table2-paginator';
import ToolkitProvider, { Search } from 'react-bootstrap-table2-toolkit';
import columns from './columns'
const Summary = () => {
const location = useLocation()
const locationName = location['pathname'].replace('/route/summary/location=', '')
// console.log('Summary, location:', locationName)
// example: location = "/route/summary/location=abc" and locationName = "abc"
// ...some code here...
return (
{/* ...some code here... */}
{/* TABLE CARD */}
{
({ paginationProps, paginationTableProps }) => (
{
toolkitProps => (
{/* ...some code here... */}
{/* TABLE ITSELF */}
{
isTableLoading ?
:
}
{/* ...some code here... */}
)
}
)
}
)
}
export default Summary
columns.js:
import React from 'react'
import { Link, useLocation } from 'react-router-dom'
// IMAGES
import IconLocation from '../../../images/icons/location.svg'
const cnColumnRenderer = (cell, row, rowIndex, formatExtraData) => {
// console.log('columns, cnColumnRenderer:', cell, row, rowIndex, formatExtraData)
const deviceVersion = cell.split('-')[1] // example: deviceVersion = "4410"
const location = useLocation()
// console.log('Summary columns, location:', location['pathname'])
// here is the pathname I wanted: "/route/cycle/location=abc" so I can take the "location" path value as below:
const locationName = location['pathname'].replace('/route/summary/location=', '') // the result is locationName = "abc"
// then put the locationName inside the Link component
return(
{/* below is the pathname I wanted: "/route/cycle/location=abc/deviceId=4410" */}
{deviceVersion}
)
}
const columns = [
{
dataField: 'deviceName',
text: 'CN',
formatter: cnColumnRenderer,
sort: true
},
{
dataField: 'convertedTotalCycle',
text: 'Cycle',
sort: true,
},
// ...some code here...
]
export default columns
Note: let me know if the question is confusing. I will try to update it.
ANSWER
Answered 2021-Jun-15 at 05:17React hooks are only valid in React functional components, not in any callbacks, loops, conditional blocks. If you need the location data in the callback it needs to be passed in.
From what I can tell it seems you need to move the columns.js
code into the main component so the location
values can be closed over in scope.
const Summary = () => {
const location = useLocation();
const locationName = location['pathname'].replace('/route/summary/location=', '')
// example: location = "/route/summary/location=abc" and locationName = "abc"
// ...some code here...
const cnColumnRenderer = (cell, row, rowIndex, formatExtraData) => {
// console.log('columns, cnColumnRenderer:', cell, row, rowIndex, formatExtraData)
const deviceVersion = cell.split('-')[1] // example: deviceVersion = "4410"
// then put the locationName inside the Link component
return(
{/* below is the pathname I wanted: "/route/cycle/location=abc/deviceId=4410" */}
{deviceVersion}
);
};
const columns = [
{
dataField: 'deviceName',
text: 'CN',
formatter: cnColumnRenderer,
sort: true
},
{
dataField: 'convertedTotalCycle',
text: 'Cycle',
sort: true,
},
// ...some code here...
];
return (
...
);
QUESTION
Using "react-router-dom": "^5.2.0" and "react": "16.8.6",
I have this:
and in the Users component:
const param = useParams();
console.log(param);
So if I enter /users
or /users/10
always param renders as empty object. What am I missing here?
ANSWER
Answered 2021-Jun-14 at 19:41The Switch
component will only render it's first match.
The first Route
that matches the path /users/10
is .
This means that even though you have a second Route
that says the "10" should be a param called id
, its ignoring it and treating it as the first Route
does which has no params.
You can easily correct this behavior by using the exact
prop on the first Route
:
This will instruct react-router
to only match that route if the URL matches the path
exactly, and will allow /users/10
to pass down to the Route
you actually want it to match. Then you will have the params available that you expect.
QUESTION
I have a fairly simple shopping app (the Odin Project Shopping Cart project) using react-router-dom. I am keeping the contents of the shopping cart in App component state, but when a new route is rendered, the component state is lost. How do I get the state to persist across route changes?
My App.js looks like this:
import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import "./style.scss";
import Items from "./components/Items.js";
import Home from "./components/Home.js";
import Nav from "./components/Nav.js";
import Cart from "./components/Cart.js";
class App extends Component {
constructor(props) {
super(props);
this.state = {
numItemsInCart: 0,
itemsInCart: {},
totalPrice: 0,
};
}
addToCart = (event) => {
event.preventDefault();
const target = event.target.parentNode;
const { vin, price } = target.dataset;
const number = parseInt(target.quantity.value);
this.setState({ numItemsInCart: this.state.numItemsInCart + number });
if (this.state.itemsInCart.hasOwnProperty(vin)) {
this.setState({
itemsInCart: {
...this.state.itemsInCart,
[vin]: this.state.itemsInCart[vin] + number,
},
});
} else {
this.setState({
itemsInCart: { ...this.state.itemsInCart, [vin]: number },
});
}
this.setState({
totalPrice: this.state.totalPrice + parseFloat(price) * number,
});
};
render() {
return (
);
}
}
export default App;
...and the github repo is here.
The Nav.js
is below:
const Nav = (props) => {
return (
- Home
- Shop
-
{props.numItemsInCart}
${props.totalPrice}
);
};
ANSWER
Answered 2021-Jun-13 at 16:18useContext
hook: React context
Redux
: Official Redux document
And btw, react-router supports passing states as props but I don't recommend it
QUESTION
I'm working on a feature where client get's discount when buying a package.
The item on the left is fixed and doesn't change. It comes in package with the item on the right where client can choose a snowboard:
All I need is that when client chooses a size, but then swipes to the next snowboard the size chosen from the previous snowboard would be set back to default 'CHOOSE SIZE OPTION'.
Here is the code of the Parent Component:
import React, { useState, useEffect } from 'react';
// Material UI
import { makeStyles } from '@material-ui/core/';
// React Responsive Carousel
import { Carousel } from 'react-responsive-carousel';
import '../../../../../../node_modules/react-responsive-carousel/lib/styles/carousel.min.css'
// Component
import PackageProd from './PackageProd/packageProd';
const useStyles = makeStyles({
packageCard: {
maxWidth: 345,
height: '100%'
},
});
const Packages = (props) => {
const classes = useStyles();
const [defaultProd, setDefaultProd] = useState({ size: 'CHOOSE THE SIZE', discount: '0', price: '0', barcode: 'default' });
function handleSetProd(val){
setDefaultProd(val)
}
return {item}}
onChange={(val)=>{
setDefaultProd({ size: 'CHOOSE THE SIZE', discount: '0', price: '0', barcode: 'default' })
}}
>
{props._packages.map((prod, i)=>{
return
})}
}
export default Packages;
I'm using a npm package Carousel that comes with an inbuilt method onChange that fires every time you swipe. So it set the defaultProd every time I swipe to the next snowboard or previous one.
Here is the child components:
import React, { useEffect, useState } from 'react';
// Material UI
import { makeStyles, Grid, Card, CardContent, CardMedia,
Typography, CardActions, Button, FormControl, InputLabel,
Select, } from '@material-ui/core/';
import { display } from '@material-ui/system';
// React Router
import { Link } from "react-router-dom";
// Knight Demon
import knightDemon from '../../../../../../assets/icons/knight_demon.png';
// Price Format
const { format } = require('number-currency-format');
const useStyles = makeStyles({
sizes: {
minWidth: '100%'
},
media: {
height: '20rem',
objectFit: 'contain'
},
text: {
color: 'black'
},
price: {
color: 'green'
},
redPrice: {
color: 'red',
textDecoration: 'line-through'
},
});
const PackageProd = (props) => {
const classes = useStyles();
const [prodDetails, setProdDetails] = useState({});
const handleChange = (event) => {
var specificProd = JSON.parse(event.target.value)
props._handleSetProd(specificProd)
};
const PriceWithDiscount = () =>
{format(props._defaultProd.price, {
currency: 'isk',
showDecimals: 'NEVER',
thousandSeparator: ' '
})}
{format(Math.ceil(parseInt(props._defaultProd.price) - (parseInt(props._defaultProd.price) * props._defaultProd.discount / 100)), {
currency: 'isk',
showDecimals: 'NEVER',
thousandSeparator: ' '
})}
const PriceWithoutDiscount = () =>
{format(props._defaultProd.price, {
currency: 'isk',
showDecimals: 'NEVER',
thousandSeparator: ' '
})}
return
0 ? props._prod.images[0] : knightDemon}
/>
console.log(props._prod)}>
{props._prod.description}
{props._defaultProd.discount > 0 ?
:
}
{props._prod.sizepricesdiscountqty.length >= 1 &&
props._prod.sizepricesdiscountqty[0].size !== '' ?
SIZE
CHOOSE SIZE
{props._prod.sizepricesdiscountqty.map((item, i)=>{
if(parseInt(item.qty) > 0){
return
{item.size.toUpperCase()}
}
})}
:
{props._prod.sizepricesdiscountqty[0].size === '' ?
SIZE: NO SIZE :
SIZE: {props._prod.sizepricesdiscountqty[0].size.toUpperCase()}
}
}
}
export default PackageProd;
The behaviour which I don't understand is the defaultValue of the Material Select Component. When I log the defaultProd which I pass from the parent it has all the values as it suppose to. When I choose the different size it changes it and sets the defaultProd in the parent to the new object.
Problem is when I swipe to a new product it should change the defaultValue to size value of defaultProd but it doesn't. Changes are reflected in price, console logs the defaultProd correctly, but size doesn't change to 'CHOOSE SIZE' and I have no idea why it doesn't reflect the change as it should. Here is the visual example:
- I choose the size and the changes are reflect both in price and the size and I successfully log the change:
But then I swipe to the next snowboard and swipe back to the previous one. Price reflect the change. defaultProd is logged correctly, but size doesn't change:
What I tried so far was to try and force the re-render with:
const [, updateState] = useState();
const forceUpdate = useCallback(() => updateState({}), []);
and fire them inside useEffect() in child component. I tried using value
instead of defaultValue
but when changing the size it wouldn't work and would just show CHOOSE SIZE
all the time. At this point I don't understand how defaultValue in material Select works and why it doesn't reflect changes.
ANSWER
Answered 2021-Jun-14 at 08:56In child component I changed defaultValue
to value
in Select, deleted native
and used renderValue
function. So my child component code in Select looks like this:
JSON.parse(val).size}
onChange={handleChange}
>
CHOOSE SIZE
{props._prod.sizepricesdiscountqty.map((item, i)=>{
if(parseInt(item.qty) > 0){
return
{item.size.toUpperCase()}
}
})}
Now the value is being reflected on rerendering.
QUESTION
I am trying to serve my react app from Nodejs, but I am getting a GET
error which is odd because when I run npm start and run the react start script all works well, but once I use node.js it doesn't work. Also if I navigate to a route by typing it in or trying to navigate backward it throws an error. For example, when you first navigate to the homepage it takes you to a login page, and if I go to another page and then hit back it throws a GET
error even though it worked beforehand.
const express = require('express');
const cors = require('cors');
const path = require('path');
const app = express();
require('dotenv').config()
app.use(express.static(path.join(__dirname, 'build')));
app.use(express.json());
app.use(cors());
app.get('/', async (req,res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
app.listen(3000, () => {
console.log(`Server listening on 3000`);
});
*/
import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import { Router, Route, Switch, Redirect } from "react-router-dom";
import { Auth0Provider } from "@auth0/auth0-react";
// core components
import Admin from "layouts/Admin.js";
import Authentication from 'layouts/Authentication';
import DashboardPage from "views/Dashboard/Dashboard.js";
import UserProfile from "views/UserProfile/UserProfile.js";
import "assets/css/material-dashboard-react.css?v=1.9.0";
const hist = createBrowserHistory();
ReactDOM.render(
,
,
document.getElementById("root")
);
// @material-ui/icons
import Dashboard from "@material-ui/icons/Dashboard";
import Person from "@material-ui/icons/Person";
// core components/views for Admin layout
import DashboardPage from "views/Dashboard/Dashboard.js";
import UserProfile from "views/UserProfile/UserProfile.js";
import Authentication from './layouts/Authentication';
const dashboardRoutes = [
{
path: "/dashboard",
name: "Invoice Dashboard",
icon: Dashboard,
component: DashboardPage,
},
{
path: "/login",
name: "Login",
icon: Dashboard,
component: Authentication
},
{
path: "/user",
name: "User Profile",
icon: Person,
component: UserProfile,
}
];
export default dashboardRoutes;
ANSWER
Answered 2021-Jun-13 at 23:09This behavior is coming from your express
app in the node.js server.
See your statement:
app.get('/', async (req,res) => {
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
Your app is only returning the index.html
file when you request the path '/'
. Basically, your react router is only established with an initial request to '/'
- allowing react Link
(e.g) elements to route correctly thereafter. This explains why typing in a deeplink (e.g '/example-path'
) and hitting the back button raise errors.
Structure your express routes to handle specific URLs, and return with the index.js
file for all others. This will allow react router to handle your front end routes, and still allow express to handle the back end routes.
// An example api endpoint that returns a list of items
app.get('/api/getList', (req, res) => {
var list = ["item1", "item2", "item3"];
res.json(list);
console.log('Sent list of items');
});
// Handles any requests that don't match the ones above
app.get('*', (req, res) =>{
res.sendFile(path.join(__dirname, 'build', 'index.html'));
});
Community Discussions, Code Snippets contain sources that include Stack Exchange Network
Vulnerabilities
No vulnerabilities reported
Install react-router
Support
Find, review, and download reusable Libraries, Code Snippets, Cloud APIs from over 650 million Knowledge Items
Find more librariesExplore Kits - Develop, implement, customize Projects, Custom Functions and Applications with kandi kits
Save this library and start creating your kit
Share this Page