Need to change a state variable within another component in React - javascript

I need to change the value mainPageView inside the UserProfile and ChangePassword Components how to achieve that? In further I want to change mainPageView value to false when clicking a button inside the UserProfile and change it to true when clicking a button inside the ChangePassword. Here is my code
import * as React from "react";
import List from "#mui/material/List";
import ListItem from "#mui/material/ListItem";
import ListItemText from "#mui/material/ListItemText";
import ListItemAvatar from "#mui/material/ListItemAvatar";
import Avatar from "#mui/material/Avatar";
import Box from "#mui/material/Box";
import AccountCircleIcon from "#mui/icons-material/AccountCircle";
import Typography from "#mui/material/Typography";
import HomeIcon from "#mui/icons-material/Home";
import CakeIcon from "#mui/icons-material/Cake";
import Axios from "axios";
import { useState, useEffect, useContext } from "react";
import { LoginContext, UserContext } from "../../../Helper/UserContext";
import { Button } from "#mui/material";
import UserProfile from "./Profile";
import ChangePassword from "./Profile";
export default function MainProfile() {
const { cookies } = useContext(LoginContext);
const employee_id = cookies.emp_id;
const [mainPageView, setMainPageView] = useState(true);
return (
<div>
{mainPageView && <UserProfile />}
{!mainPageView && <ChangePassword />}
</div>
);
}
A solution (code snippet) which describes the USerProfile and ChangePassword Component

Pass parent method as a props
e.g.
{mainPageView && <UserProfile updatevalue ={setMainPageView}/>}
{!mainPageView && <ChangePassword updatevalue ={setMainPageView} />}
const ChangePassword = (props) => {
return (
<div>
<h1 onClick= { () =>
props.updatevalue(false>)
}
> Something</h1>
</div>
)
}
export default ChangePassword;

Related

Uncaught TypeError: Cannot read properties of undefined (reading 'params') while using axios and react-router-dom

It's the HomePage component of ReactJS
import React from 'react';
import axios from 'axios';
import { useState, useEffect } from 'react';
import { useNavigate,useParams } from 'react-router-dom';
import { Main } from '../components/Main';
import { Controls } from '../components/Controls';
import { ALL_COUNTRIES } from '../config';
import { List } from '../components/List';
import { Card } from '../components/Card';
import { Details } from './Details';
export const HomePage = () => {
const [countries,setCountries] = useState([]);
const navigate = useNavigate();
useEffect(() => {
axios.get(ALL_COUNTRIES).then(({data})=>setCountries(data))
},[]);
return (
<>
<Controls/>
<List>
{
countries.map((c) => {
const countryInfo = {
img: c.flags.png,
name: c.name,
info: [
{
title:'Population',
description:c.population.toLocaleString(),
},
{
title:'Region',
description:c.region,
},
{
title:'Flag',
description:c.capital,
},
],
};
return (
<Card
key={c.name}
onClick={(e) => {
navigate('/country/${c.name}');
}}
{...countryInfo}
/>
)
})
}
</List>
</>
);
};
It's second components Details
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = ({match,params}) => {
const { name } = useParams();
return (
<div>
Details {match.params.name}
</div>
);
};
config.js
const BASE_URL = 'https://restcountries.com/v2/';
export const ALL_COUNTRIES=BASE_URL+"all?fields=name,flags,population,capital,region";
export const searchByContry=(name)=>BASE_URL+'name/'+name;
export const filterByCode=(code)=>BASE_URL+'alpha?code'+code.join('');
APP.jsx
import React from 'react';
import ReactDOM from 'react-dom';
import axios from 'axios';
import { Route,Routes,Router,useParams} from 'react-router-dom';
import {useState, useEffect} from 'react';
import './App.css';
import styled from 'styled-components';
import Header from './components/Header';
import { Main } from './components/Main';
import {NotFound} from './pages/NotFound';
import { HomePage } from './pages/HomePage';
import { Details } from './pages/Details';
function App() {
return (
<>
<Header/>
<Main>
<Routes>
<Route path="/" element={<HomePage/>}/>
<Route path="country/:name" element={<Details/>}/>
<Route path="*" element={<NotFound/>}/>
</Routes>
</Main>
</>
);
}
export default App;
HomePage itself looks like this
but when I click on flag/card it sends me on second page as expected but gives me this error
[2]:https://i.stack.imgur.com/39HEw.png
Also, I'm using react-router-domV6 and Axios
and this API https://restcountries.com/v2/all
also both Components are in
APP.js
Details is trying to read params from an undefined object, props.match in this case.
<Route path="country/:name" element={<Details />} /> // <-- no props passed!
...
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = ({ match, params }) => { // <-- match undefined
const { name } = useParams();
return (
<div>
Details {match.params.name} // <-- Oops, can't read params of undefined
</div>
);
};
Remove the props and access the values returned from the useParams hook.
import React from 'react';
import { useParams } from 'react-router-dom';
export const Details = () => {
const { name } = useParams();
return (
<div>
Details {name}
</div>
);
};
The target path is also malformed. The code navigate('/country/${c.name}') is navigating to the string literal "/country/${c.name}", which is likely not what you meant to do. Fix this to use a string template literal instead to inject the c.name value into the target path.
navigate(`/country/${c.name}`) // note the backticks instead of single quotes
I oftentimes find it useful/helpful to use the generatePath utility function to create path values.
Example:
import { generatePath, useNavigate } from 'react-router-dom';
...
const path = generatePath("/country/:name", { name: c.name });
navigate(path);

How to render the text used on one page on another page in ReactJS? [duplicate]

This question already has answers here:
How to pass data from a page to another page using react router
(5 answers)
Closed 8 months ago.
Basically, I just want to display the name of the User entered inside the textbox on another page. I am a beginner in ReactJS so bare with me.
I am entering the name in a textbox in Enter.js and upon clicking the button it is redirecting me to Preview.js where I want the name to be displayed!!!
Here is my code of App.js
//import logo from './logo.svg';
import './App.css';
import React from 'react';
//import { useState } from 'react';
//import { useNavigate } from "react-router-dom";
//import Preview from './components/Preview';
import {
//BrowserRouter as Router,
Routes,
Route
} from 'react-router-dom';
import Enter from './components/Enter';
function App() {
//const [text,setText] = useState();
return (
<Routes>
<Route path="/" element={<Enter/>}/>
</Routes>
);
}
export default App;
Code of Enter.js
import React from 'react';
import { useState } from 'react';
import { useNavigate } from 'react-router-dom';
//import PropTypes from 'prop-types'
import {
//BrowserRouter as Router,
Routes,
Route
//Link
} from 'react-router-dom';
import Preview from './Preview';
export default function Enter() {
const navigate = useNavigate();
const preview = () => {
navigate("/preview");
}
const [text,setText] = useState('');
const handleChange = (event) => {
setText(event.target.value);
}
return (
<>
<div className="container my-3">
<label htmlFor="exampleFormControlInput1" className="form-label">Name:</label>
<input className="form-control" placeholder="Enter your full Name" onChange={handleChange} value={text}/>
<button className="btn btn-primary my-4" onClick={preview}>Submit</button>
</div>
<Routes>
<Route path="/preview" element={<Preview text1={text}/>}/>
</Routes>
</>
)
}
Code of Preview.js
import React from 'react';
import PropTypes from 'prop-types';
export default function Preview(props) {
return (
<div className="container my-3">
<h3>Name:{props.text1}</h3>
</div>
)
}
Preview.propTypes = {
text1: PropTypes.string
}
Thankyou for your help in advance!!!
The best way to achieve this is to pass query parameters on redirection like this:
const preview = () => {
navigate(/preview?q=${text});
}
And then on the preview page you can get the value of query param and display it on the page.
import { useSearchParams } from "react-router-dom"
let [searchParams, setSearchParams] = useSearchParams()
const text= searchParams.get("q")
This is how you can get the params
Best option is to use React Context to save your text on global state , then read that from your Preview Component, or any component you want.

How to pass data by button click in redux react js

I'm new to redux. I have three components are TextField , Button and View. I just stored textfield data in redux configureStore, How to pass data by button click from button component to view component. Im using context how to change in redux.
Codesandbox link using redux
Here I tired but I want to diplay only when button click.
CodeSanbox Link using Context
Here is the solution I make ready for you
App.js
import "./styles.css";
import Tfield from "./Tfield";
import ButtonSubmit from "./ButtonSubmit";
import TypoValue from "./TyoValue";
import React, { useCallback, useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { updateValue } from "./features/user";
export default function App() {
const dataFromRedux = useSelector((state) => state.user.value);
console.log(dataFromRedux);
// useRef to prevent re-rendering
const inputRef = React.useRef(undefined);
const dispatch = useDispatch();
const handleUpdate = () => {
dispatch(updateValue(inputRef.current.value));
};
return (
<div className="App">
<Tfield inputRef={inputRef} />
<ButtonSubmit handleUpdate={handleUpdate} />
<TypoValue />
</div>
);
}
Tfield.js
import "./styles.css";
import * as React from "react";
import TextField from "#mui/material/TextField";
export default function Tfield({ inputRef }) {
console.log("Textfield");
return (
<div>
<TextField
inputRef={inputRef}
label="Enter Name"
/>
</div>
);
}
BtnPage.js
import React from "react";
import { useDispatch, useSelector } from "react-redux";
import { updateValue } from "./features/Updater";
export default function BtnPage({handleUpdate}) {
return (
<div>
<button onClick={() => handleUpdate()}> Update </button>
</div>
);
}
TFPage.js
import React, { useEffect, useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { updateValue } from "./features/Updater";
export default function TFPage({myTxt, setMyTxt}) {
//const myData = useSelector((state) => state.update.value);
// const [myTxt, setMyTxt] = useState(myData.text);
//const dispatch = useDispatch();
const handleChange = (char) => {
setMyTxt(char);
//dispatch(updateValue(myTxt));
};
// useEffect(() => {
// // console.log('useEff - render');
// dispatch(updateValue({ text: myTxt }));
// }, [myTxt]);
return (
<div>
<input
value={myTxt}
placeholder="Enter Some Text"
onChange={(e) => handleChange(e.target.value)}
/>
</div>
);
}
ViewPage.js
import React from "react";
import { useSelector } from "react-redux";
export default function ViewPage() {
const myData = useSelector((state) => state.update.value);
console.log(myData);
return (
<div>
<h1> {myData} </h1>
</div>
);
}
As per your Codesandbox link using redux Code.
I think you have to change from import updateValue from "./features/Updater"; to import { updateValue } from "./features/Updater";
And it works fine for me
Your current App.js file
import "./styles.css";
import TFPage from "./TFPage";
import BtnPage from "./BtnPage";
import ViewPage from "./ViewPage";
import { useSelector, useDispatch } from "react-redux";
import updateValue from "./features/Updater";
import { useState, React } from "react";
export default function App() {
const myData = useSelector((state) => state.update.value);
const [myTxt, setMyTxt] = useState(myData.text);
const dispatch = useDispatch();
const handleUpdate = () => {
console.log(myData);
dispatch(updateValue(myTxt));
};
return (
<div className="App">
<TFPage setMyTxt={setMyTxt} myTxt={myTxt} />
<BtnPage handleUpdate={handleUpdate} />
<ViewPage />
</div>
);
}
Your App.js file should look like below
import "./styles.css";
import TFPage from "./TFPage";
import BtnPage from "./BtnPage";
import ViewPage from "./ViewPage";
import { useSelector, useDispatch } from "react-redux";
import { updateValue } from "./features/Updater";
import { useState, React } from "react";
export default function App() {
const myData = useSelector((state) => state.update.value);
const [myTxt, setMyTxt] = useState(myData.text);
const dispatch = useDispatch();
const handleUpdate = () => {
console.log(myData);
console.log(myTxt);
dispatch(updateValue(myTxt));
};
return (
<div className="App">
<TFPage setMyTxt={setMyTxt} myTxt={myTxt} />
<BtnPage handleUpdate={handleUpdate} />
<ViewPage />
</div>
);
}
You can also get a better understanding of the redux toolkit from this given doc Redux toolkit explaination for a better understanding
Your reducer has the following structure:
initialState: { value: { text: "" } }
But you are triggering an action like this:
dispatch(updateValue("youy text here"));
When it should be like this:
dispatch(updateValue({ text: "your text here" }));

Reuse ReactJS component

I have built a ReactJS component for rendering emoction. Separate component can be built for each emoction, but I want to use one component but pass separate emoction as required.
This is what works so far:
emoction.js
import { faHeart } from "#fortawesome/free-solid-svg-icons";
import { faHeartBroken } from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { useState } from 'react';
const Emoction = () => {
return (
<FontAwesomeIcon icon={faHeart} />
);
};
export default Emoction;
emoction_hb.js
import { faHeart } from "#fortawesome/free-solid-svg-icons";
import { faHeartBroken } from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { useState } from 'react';
const EmoctionHb = () => {
return (
// <input type="text" />
<FontAwesomeIcon icon={faHeartBroken} />
);
};
export default EmoctionHb;
Now, I am bundling these two components as:
expanded_content.js
import Emoction from "../emoctions/emoctions";
import EmoctionHb from "../emoctions/emoctions_hb";
import styled from "#emotion/styled";
import { faHeartBroken } from "#fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "#fortawesome/react-fontawesome";
import React, { Component } from 'react';
const Merged = styled.div`
display: flex;
flex-direction: row;
justify-content: flex-start;
`;
const expandedContent = () => {
return(
<div>
<Merged>
<Emoction/>
<EmoctionHb/>
</Merged>
</div>
)
};
export default expandedContent;
which when I rendered using App.js
import React from 'react';
import ReactDOM from 'react-dom';
import {BrowserRouter as Router, Switch, Route} from 'react-router-dom';
import expandedContent from './components/merged_component/expanded_content'
class App extends React.Component {
render(){
return(
<Router>
<>
<Route path='/ExpandedContent' exact component={expandedContent}/>
</>
</Router>
)
}
}
export default App;
gives me.
What I am trying to do is that instead of creating a component called emoctions_hb.js I want to reuse emoction.js by passing "faHeartBroken" as the value in it.
If emoction.js is called without any value, I want it to use "faHeartBroken" as default value.
Tried following on to create Parent-Child relationship using https://webomnizz.com/change-parent-component-state-from-child-using-hooks-in-react/ but it did not work out for me.
Just pass the icon as a prop and set the default value to faHeartBroken:
const Emoction = ({ faIcon = faHeartBroken }) => {
return (
<FontAwesomeIcon icon={faIcon} />
);
};
It looks like you're importing useState but you're not implementing it anywhere. You could try implementing state in your expanded_content.js file and pass that down to your child component emoction.js, like this:
const ExpandedContent = () => {
const [heart, setHeart] = useState(true)
return(
<div>
<Emoction heart={heart} setHeart={setHeart}/>
</div>
)
};
export default ExpandedContent;
Notice that you will need to change the name of your component. See the docs here https://reactjs.org/docs/hooks-rules.html.
Then, inside of your Emoction component you will have access to heart which is set to true by default and you can also implement some logic to toggle the state using the function setHeart which is passed down from ExpandedContent:
const Emoction = ({heart, setHeart}) => {
const handleHearts = () => {
setHeart(heart => !heart)
}
return (
heart ? <FontAwesomeIcon icon={faHeart} /> : <FontAwesomeIcon icon={faHeartBroken} />
);
};
export default Emoction;
By using a ternary statement to return your component you can decide to show faHeart or faHeartBroken depending on the current state. All you need to do is add the functionality wherever you need it.

Taking input and outputing it Inside of an expansion Panel in React js

So I am trying to take a user input and output that through Material UI expansion panels this is currently what i have to do so. but im getting an error saying this.props.GitInput is not a function
import React, { Component } from 'react';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import RaisedButton from 'material-ui/RaisedButton';
import IdentificationField from './IdentificationField';
import DataGraph from './DataGraph';
import PropTypes from 'prop-types';
class AssociateIdentification extends Component {
constructor() {
super();
this.state = {
GitInput: '',
};
this.GitInput = this.GitInput.bind(this);
}
componentDidMount() {
if (this.props.id !== 0) {
this.GitInput();
}
}
componentDidUpdate(_, prevState) {
if (prevState.id !== this.state.id) {
this.GitInput();
}
}
GitInput() {
this.props.GitInput(this.state.id);
}
render() {
return (
<div>
<input type="text" onChange={this.handleSubmit} />
{this.state.GitInput}
</div>
);
}
}
export default (AssociateIdentification);
and I am outputing it like this on a seperate component.
import React from 'react';
import { MockGit } from './Constants';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import GitInput from './AssociateIdentification';
const GitData = () => {
return (
<ExpansionPanel>
<ExpansionPanelSummary expandIcon={<ExpandMoreIcon />}>
<Typography> {MockGit} </Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Typography>
{GitInput}
</Typography>
</ExpansionPanelDetails>
</ExpansionPanel>
);
};
export default (GitData);
I know this is fairly simple but I am struggling to get it to work.

Categories

Resources