Hi guys, I'm trying to code little app. I am trainee programmer. I need help to understand how to use props on my app. I'm currently using one component from CodePen and I fetched the data from jsonplaceholder. But I don't know how to pass props between this component and App.js. It was no problem with easier components but here is lot of methods and events. With this tagged input I want to add or delete items.
import React from "react";
import StateFullComponent from "./components/StateFullComponent";
import StatelessComponent from "./components/StatelessComponent";
import TagInput from "./components/TagInput";
function App() {
return (
<div>
<StatelessComponent
props1={"String"}
props2={1}
props3={true}
props4={JSON.stringify({ value: "value", key: 1 })}
/>
<StateFullComponent items={["apple", "orrange", "pear", "male"]} />
<TagInput />
</div>
);
}
export default App;
import React, { Component } from "react";
export default class TagInput extends Component {
constructor(props) {
super(props);
this.state = {
users: [],
focused: false,
input: ""
};
this.handleInputChange = this.handleInputChange.bind(this);
this.handleInputKeyDown = this.handleInputKeyDown.bind(this);
this.handleRemoveItem = this.handleRemoveItem.bind(this);
}
componentDidMount() {
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => {
return response.json();
})
.then(result => {
this.setState({
users: result
});
});
}
add() {
let value = Math.floor(Math.random() * 10 + 1);
let users = this.state.users;
users.push(value);
this.setState({ users: users });
}
handleInputChange(evt) {
this.setState({ input: evt.target.value });
}
handleInputKeyDown(evt) {
if (evt.keyCode === 13) {
const { value } = evt.target;
this.setState(state => ({
users: [...state.users, value],
input: ""
}));
}
if (
this.state.users.length &&
evt.keyCode === 8 &&
!this.state.input.length
) {
this.setState(state => ({
users: state.users.slice(0, state.users.length - 1)
}));
}
}
handleRemoveItem(index) {
return () => {
this.setState(state => ({
users: state.users.filter((user, i) => i !== index)
}));
};
}
render() {
console.log(this.props, ":::::::::::");
const { users } = this.state;
const userId = users.map((user, id) => <li key={id}>{user.name}</li>);
const styles = {
container: {
border: "1px solid #ddd",
padding: "5px",
borderRadius: "5px"
},
items: {
display: "inline-block",
padding: "2px",
border: "1px solid blue",
fontFamily: "Helvetica, sans-serif",
borderRadius: "5px",
marginRight: "5px",
cursor: "pointer"
},
input: {
outline: "none",
border: "none",
fontSize: "14px",
fontFamily: "Helvetica, sans-serif"
}
};
return (
/* <div>
<ul>{userId}</ul>
<button onClick={this.handleRemoveItem().bind(this)}>add</button>
</div> */
<label>
<ul style={styles.container}>
{this.state.users.map((user, i) => (
<li
key={i}
style={styles.users}
onClick={this.handleRemoveItem(i).bind(this)}
>
{user}
<span>(x)</span>
</li>
))}
<input
style={styles.input}
value={this.state.input}
onChange={this.handleInputChange.bind(this)}
onKeyDown={this.handleInputKeyDown.bind(this)}
/>
</ul>
</label>
);
}
}
In your componentDidMount you are fetching data, and getting back an array of objects, and setting the state value users to the array of objects. That's all good and exactly what you should be doing.
The problem is in the render method when you are looping through the array of users. Remember that each user in the array is an object. Look at the jsx you have within the li element. You are rendering the user object, and an object is an invalid react child. Instead, you need to render the particular fields from the object.
Example, if the object contains a name field, and an email field, render {user.name} or {user.email}. That way you can render the particular fields of data from the user object.
<li
key={i}
style={styles.users}
onClick={this.handleRemoveItem(i).bind(this)}
>
Name: {user.name}
Email: {user.email}
Id: {user.id}
<span>(x)</span>
</li>
It seems you may still have some questions about passing props to a component. This only addresses the particular error you are seeing. If you still have questions let me know.
Related
I have the stake component that is rendered 4 times in the parent class component. I am trying to pass valueNewStake as prop to its parent component and group all the inputs in one common array (see allStakes). For a reason I am not able to change the state and also the dom does not render the button next to the component. Can anyone explain me why it is happening as I am new in react. Thanks
import React, { Component } from 'react';
import Stake from './stake';
class FetchRandomBet extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
bet: null,
value: this.props.value,
allStakes: ['']
};
}
async componentDidMount() {
const url = "http://localhost:4000/";
const response = await fetch(url);
const data = await response.json();
this.setState({
loading: false,
bet: data.bets,
});
}
render() {
const { valueProp: value } = this.props;
const { bet, loading } = this.state;
if (loading) {
return <div>loading..</div>;
}
if (!bet) {
return <div>did not get data</div>;
}
return (
< div >
{
loading || !bet ? (
<div>loading..</div>
) : value === 0 ? (
<div className="bet-list">
<ol>
<p>NAME</p>
{
bet.map(post => (
<li key={post.id}>
{post.name}
</li>
))
}
</ol>
<ul>
<p>ODDS</p>
{
bet.map(post => (
<li key={post.id}>
{post.odds[4].oddsDecimal}
<div className="stake-margin">
<Stake
allStakes={this.props.valueNewStake}
onChange={() => { this.setState({ allStakes: [...this.props.valueNewStake] }) }}
>
<button>ok</button>
</Stake>
</div>
</li>
))
}
</ul>
</div>
import React, { useState } from 'react';
import CurrencyInput from 'react-currency-input-field';
function Stake() {
const [newStake, setStake] = useState(['']);
const changeStake = (e) => {
setStake(e.target.value)
}
return (
<>
<CurrencyInput
onChange={changeStake}
valueNewStake={newStake}
style={{
marginLeft: "40px",
width: "50px"
}}
placeholder="Stake"
decimalScale={2}
prefix="£"
/>
{newStake}
</>
);
}
export default Stake;
You're not passing your props to your Stake component
function Stake({ allStakes, onChange }) {
// do something with your props here
const [newStake, setStake] = useState(['']);
const changeStake = (e) => {
onChange()
setStake(e.target.value)
}
return (
<>
<CurrencyInput
onChange={changeStake}
valueNewStake={newStake}
style={{
marginLeft: "40px",
width: "50px"
}}
placeholder="Stake"
decimalScale={2}
prefix="£"
/>
{newStake}
</>
);
}
I am new to react and am using react-select for selecting the respective departments. I am trying to validate the select dropdown such that if select dropdown is empty it will give an error message. I am not sure how to do that exactly. It is showing this error:
Departments.continue
D:/react_bpms1/src/components/Departments.js:69
66 | this.setState({ selectedOptions });
67 | };
68 | continue = e => {
> 69 | if (document.getElementById("Departments").value.length < 1) {
| ^ 70 | document.getElementById("departments").style.visibility = "visible";
71 | document.getElementById("Departments").style.border = "1px solid red";
72 | } else {
But here is what I am doing:
const Departments = [
{ label: "OneIT", value: "OneIT" },
{ label: "HR", value: "HR" },
{ label: "Vigilance", value: "Vigilance" },
{ label: "Ethics", value: "Ethics" },
{ label: "Corporate Services", value: "Corporate Services" },
{ label: "Legal", value: "Legal" },
{ label: "Sports", value: "Sports" },
{ label: "TQM", value: "TQM" },
{ label: "Iron Making", value: "Iron Making" },
{ label: "TMH", value: "TMH" }
];
class MultiSelect2 extends Component {
state = {
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
render() {
const { selectedOption } = this.state;
return (
<div className="container">
<div className="row">
<div className="col-md-2"></div>
<div className="col-md-8">
<span>Select Department</span>
<Select
id="Departments"
htmlFor="Departments"
value={selectedOption}
options={Departments}
onChange={this.handleChangeField}
isMulti
/>
{this.state.selectedOptions.map(o => (
<p>{o.value}</p>
))}
</div>
<div className="col-md-4"></div>
</div>
</div>
);
}
}
export default MultiSelect2;
Here is where I am calling the Multiselect option:
export class Departments extends Component {
state = {
rows: [],
idx: [],
selectedOptions: []
};
handleChangeField = selectedOptions => {
this.setState({ selectedOptions });
};
continue = e => {
if (document.getElementById("Departments").value.length < 1) {
document.getElementById("departments").style.visibility = "visible";
document.getElementById("Departments").style.border = "1px solid red";
} else {
e.preventDefault();
this.props.nextStep();
}
};
back = e => {
e.preventDefault();
this.props.prevStep();
};
render() {
const { values, handleChange } = this.props;
const { selectedOption } = this.state;
const {
values: {
Title,
Details,
What,
Why,
How,
Status,
Cost,
Benefits,
Kpi_Before,
Kpi_After,
UOM_Before,
UOM_After,
Base_After,
Target_After,
dateTime_After,
Base_Before,
Target_Before,
Time,
dateTime,
departments,
Departments,
selectedOptions
}
} = this.props;
return (
<MuiThemeProvider theme={theme}>
<React.Fragment>
<div className={useStyles.root}>
<AppBar position="static">
<Toolbar>
<Typography
gutterBottom
align="center"
style={{ width: "100%", alignItems: "center" }}
>
Select Departments
</Typography>
</Toolbar>
</AppBar>
</div>
<br />
<br />
<Grid container>
<Grid item xs={6}>
<MultiSelect2
style={{ width: "80%" }}
id="Departments"
onChange={this.handleChangeField}
value={selectedOption}
/>
<label
id="departments"
style={{ visibility: "hidden", color: "red" }}
>
Select Applicable departments
</label>
</Grid>
As #sandeeppradhan you have to stop using these accessors, and think DATA driven ie change the states / props and display them through your interface, dont change styles as you are doing because the dom may change at anytime. And this is a source of bug as the component may not be attached to the dom or a child component may not be ready. Tbh, you are a bit too far in the wrong to make minor update to your code to fix the isssue
To answer more specifically to your question : probably the MultiSelect2 is not rendered when the event occurs.
Bad solution but may interest you : merge the MultiSelect2 inside Departments and use ref + state
ex :
export class Departments extends Component {
constructor(props) {
super(props);
this.state={
departmentsStyle:{}
};
this.departmentsRef = React.createRef();
}
//...
continue = e => {
if (this.departmentsRef.current && this.departmentsRef.current.value.length < 1) {
this.setState({
departmentsStyle:{
border:"1px solid red",
visibility : "visible"
}
});
} else {
this.setState({
departmentsStyle:{}
});
e.preventDefault();
this.props.nextStep();
}
};
//.... ETC ETC
render() {
//...
return (
///...
//The ref is forwarded to the root element
//(if it does not work use inputRef={departmentsRef})
<Select ref={departmentsRef} style={this.state.departmentsStyle}
//...
)
}
Best solution I think : At this point the only think I would advice is if possible to look at Formik and transfer the FormikBag to the MultiSelect2. You could then manage better the components with the state of the form.
https://jaredpalmer.com/formik/docs/overview
good luck, all the best
So I have two components, Person and App, the person component has some inline CSS styling that I was to use with react, but I am getting the following error.
Module '"../../../../../../Users/7oss/Desktop/ReactTutorials/my-first-portfolio/node_modules/#types/radium"' has no exported member 'StyleRoot'.ts(2305)
I am trying to add #media styling to the Person Component.
I have tried doing Radium.StyleRoot instead of StyleRoot, but I got the following error:
Objects are not valid as a React child (found: object with keys {#media (min-width: 500px)}). If you meant to render a collection of children, use an array instead.
Here is the App Component:
import React, { Component, ChangeEvent } from "react";
import "./App.css";
import Person from "./Components/Person/Person";
import Radium, { StyleRoot } from "radium";
class App extends Component {
state = {
persons: [
{ id: "hoba", name: "Hosam", age: 24 },
{ id: "hoba1", name: "Ayah", age: 18 },
{ id: "hoba2", name: "Test", age: 20 }
],
ShowPersons: false
};
deletePersonHandler = (personIndex: any) => {
// const persons = this.state.persons.slice(); this is one way
const persons = [...this.state.persons]; // Another way
persons.splice(personIndex, 1);
this.setState({ persons: persons });
};
nameChangeHandler = (event: any, id: any) => {
// console.log('Was clicked!!');
// this.state.persons[0].name = "7ossam" DON'T DO THIS!!! USE SETSTATE()
const personIndex = this.state.persons.findIndex(p => {
return p.id === id;
});
const person = { ...this.state.persons[personIndex] };
person.name = event.target.value;
const persons = [...this.state.persons];
persons[personIndex] = person;
this.setState({
persons: persons
});
};
togglePersonsHanddler = () => {
const doesShow = this.state.ShowPersons;
this.setState({ ShowPersons: !doesShow });
};
render() {
const style = {
backgroundColor: "green",
color: "white",
font: "inherit",
border: "1px solid",
cursor: "pointer",
":hover": {
backgroundColor: "lightgreen",
color: "black"
}
};
let persons = null;
if (this.state.ShowPersons) {
persons = (
<div>
{this.state.persons.map((person, index) => {
return (
<Person
name={person.name}
age={person.age}
click={() => this.deletePersonHandler(index)}
key={person.id}
changedName={(event: any) =>
this.nameChangeHandler(event, person.id)
}
/>
);
})}
</div>
);
style.backgroundColor = "red";
style[":hover"] = {
backgroundColor: "salmon",
color: "black"
};
}
let classes = [];
if (this.state.persons.length <= 2) {
classes.push("red");
}
if (this.state.persons.length <= 1) {
classes.push("bold");
}
return (
<StyleRoot>
<div className="App">
<br />
<p className={classes.join(" ")}>Yasta garab el hoba hoba</p>
<button style={style} onClick={this.togglePersonsHanddler}>
Toggle Names
</button>
<br />
<h1>Hello, this is sam!</h1>
{persons}
</div>
</StyleRoot>
);
}
}
export default Radium(App);
And here is the Person Component:
import React, { Component } from "react";
import Radium from "radium";
import "./Person.css";
interface IPersonProps {
name: string;
age: number;
click?: any;
changedName?: any;
}
class Person extends Component<IPersonProps> {
render() {
const style = {
"#media (min-width: 500px)": {
width: "450px"
}
};
return (
<div className="Person">
{" "}
style={style}
<p onClick={this.props.click}>
{" "}
I am {this.props.name} and I am {this.props.age} years old
</p>
<p>{this.props.children}</p>
<input
type="text"
onChange={this.props.changedName}
value={this.props.name}
/>
</div>
);
}
}
export default Radium(Person);
Here is the radium package in package-lock.json:
"#types/radium": {
"version": "0.24.2",
"resolved": "https://registry.npmjs.org/#types/radium/-/radium-0.24.2.tgz",
"integrity": "sha512-AudCpKQH/csx6eB4OZhEdKf8Avm18wX8gLOig5H5iocPDPp3GRUPkQmUOXvsIYO64LyAb4CiIfSmcWUaUdvl4A==",
"requires": {
"#types/react": "*"
}
},
I am assuming that the issue is with StyleRoot isn't imported correctly somehow, but I would appreciate some input. I am also Using TypeScript
I had the same problem. I managed to solve by making the typing of the constant style explicit.
const style: Radium.StyleRules = {
'#media (min-width: 500px)': {
width: '450px'
}
};
I am having a problem related to redux.
I have 2 connected components which are:
avatar situated in the navbar which is always visible
profile which is responsible for changing the avatar image in the store
if I am right, when the store change, any connected component will re-render if needed.
In my case, when the action UPDATE_CURRENT_USER update the avatar image, the navbar avatar doesn't get the new image only after I change route or reload page.
I found a solution but many people say it's a hack,
I have put a listener on store changes in the main component and did forceUpdate()
componentDidMount() {
store.subscribe(res => this.forceUpdate());
}
and I don't want to use it since connected components are supposed to re-render on store changes.
user actions:
export const getCurrentUser = () => dispatch => {
axios.get("user").then(user => {
dispatch({
type: GET_CURRENT_USER,
payload: user.data
});
});
};
export const updateCurrentUser = user => dispatch => {
dispatch({
type: UPDATE_CURRENT_USER,
payload: user
})
}
user reducer
const initialState = {
user: {}
}
export default function (state = initialState, action) {
switch (action.type) {
case GET_CURRENT_USER:
return { ...state, user: action.payload };
case UPDATE_CURRENT_USER:
return { ...state, user: action.payload }
default:
return state;
}
}
profile component
class Profile extends Component {
render() {
const { currentUser, updateCurrentUser } = this.props;
return (
<div id="profile-container">
<ProfileSider
currentUser={currentUser}
updateCurrentUser={updateCurrentUser}
/>
<ProfileContent
currentUser={currentUser}
updateCurrentUser={updateCurrentUser}
/>
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.userReducer.user
});
export default connect(
mapStateToProps,
{ updateCurrentUser }
)(Profile);
profile sidebar child of profile
class ProfileSider extends Component {
state = { uploading: false };
triggerAvatarInput() {
$("#avatarInput").click();
}
handleChange = async event => {
this.setState({ ...this.state, uploading: true });
const avatarFormData = new FormData();
avatarFormData.append("file", event.target.files[0]);
axios
.post("uploadFile", avatarFormData)
.then(res => {
const avatarURIFormData = new FormData();
avatarURIFormData.append("avatar", res.data.fileDownloadUri);
axios
.put("user/update", avatarURIFormData)
.then(res => {
const { currentUser } = this.props;
currentUser.avatar = res.data.avatar;
this.props.updateCurrentUser(currentUser);
this.setState({
...this.state,
uploading: false,
avatar: currentUser.avatar
});
message.success("Avatar updated successfully", 3);
})
.catch(error => {
this.setState({ ...this.state, uploading: false });
message.error("Updating avatar failed!", 3);
});
})
.catch(error => {
this.setState({ ...this.state, uploading: false });
message.error("Uploading avatar failed!", 3);
});
};
render() {
const { uploading } = this.state;
const { currentUser } = this.props;
return (
<div id="profile-sider">
<div id="profile-sider-info">
<div id="profile-sider-info-avatar">
<div className="container">
<div
className="overlay-uploading"
className={
uploading ? "overlay-uploading" : "overlay-uploading hidden"
}
>
<Icon type="loading" style={{ fontSize: 50, color: "#FFF" }} />
</div>
<div className="overlay" />
<div className="overlay-text" onClick={this.triggerAvatarInput}>
<Icon type="camera" style={{ fontSize: 20 }} />
<span>Update</span>
</div>
<div
className="avatar"
style={{
backgroundImage: "url(" + currentUser.avatar + ")"
}}
></div>
<input
onChange={this.handleChange}
type="file"
accept="image/png, image/jpeg, image/jpg"
id="avatarInput"
/>
</div>
</div>
<h2 style={{ marginTop: 20, textAlign: "center" }}>
{currentUser.fullName}
</h2>
<h4 style={{ textAlign: "center" }}>{currentUser.email}</h4>
</div>
<div id="profile-sider-actions">
<div className="profile-sider-actions-item">
<Link to="/profile/courses" style={{ transition: 0 }}>
<Button type="primary" id="courses-btn">
<Icon type="read" style={{ marginRight: 15 }} />
My Courses
</Button>
</Link>
</div>
<div className="profile-sider-actions-item">
<Link to="/profile/update">
<Button type="primary" id="update-infos-btn">
<Icon type="sync" style={{ marginRight: 15 }} />
Update Infos
</Button>
</Link>
</div>
</div>
</div>
);
}
}
export default ProfileSider;
avatar component situated in navbar
class ProfileAvatar extends Component {
constructor() {
super();
this.handleClick = this.handleClick.bind(this);
this.handleOutsideClick = this.handleOutsideClick.bind(this);
this.state = {
showProfileDropdown: false
};
}
componentDidMount() {
this.props.getCurrentUser();
}
handleLogout = async () => {
try {
await auth.logout();
this.props.onLogout();
notification["success"]({
message: "You have been successfully logged out!"
});
} catch (ex) {}
};
handleClick() {
if (!this.state.showProfileDropdown) {
// attach/remove event handler
document.addEventListener("click", this.handleOutsideClick, false);
} else {
document.removeEventListener("click", this.handleOutsideClick, false);
}
this.setState(prevState => ({
showProfileDropdown: !prevState.showProfileDropdown
}));
}
handleOutsideClick(e) {
// ignore clicks on the component itself
if (this.element && this.element.contains(e.target)) {
return;
}
this.handleClick();
}
render() {
const { currentUser } = this.props;
return (
<div
className="profile-avatar"
ref={element => {
this.element = element;
}}
>
<Avatar
onClick={this.handleClick}
size="large"
style={{ color: "#f56a00", backgroundColor: "#fde3cf" }}
src={currentUser.avatar}
>
{currentUser.fullName ? currentUser.fullName.charAt(0) : null}
</Avatar>
{this.state.showProfileDropdown && (
<div className="profile-dropdown-list">
<List
className="dropdown_list dropdown-shadow "
size="small"
style={{ width: "150px" }}
bordered
itemLayout="vertical"
dataSource={[
<Link to="/profile/update" className="profile-list-item">
<List.Item className="list-item">
<Icon className="profile-icons" type="user" /> My Profile
</List.Item>
</Link>,
<Link to="/profile/courses" className="profile-list-item">
<List.Item className="list-item">
<Icon className="profile-icons" type="container" /> My
Courses
</List.Item>
</Link>,
<List.Item className="list-item">
<Icon className="profile-icons" type="question-circle" /> Ask
for Help
</List.Item>,
<List.Item className="list-item" onClick={this.handleLogout}>
<Icon className="profile-icons" type="logout" /> Log out
</List.Item>
]}
renderItem={item => item}
/>
</div>
)}
</div>
);
}
}
const mapStateToProps = state => ({
currentUser: state.userReducer.user
});
export default connect(
mapStateToProps,
{ getCurrentUser }
)(ProfileAvatar);
image: https://imge.to/i/vywTNj
There are two problems here:
You are mutating the existing object from the store
You are sending that exact same user object back into the store when you dispatch the action.
Specifically, these lines are the cause:
const { currentUser } = this.props;
currentUser.avatar = res.data.avatar;
this.props.updateCurrentUser(currentUser);
currentUser is the user object that's already in the Redux store. This code mutates the object, and inserts it back into the store.
That results in the connected component thinking nothing has actually changed.
The shortest way to fix this is to create a new user object, and insert that:
const {currentUser} = this.props;
const updatedUser = {...currentUser, avatar: res.data.avatar};
this.props.updateCurrentUser(updatedUser);
To avoid this in the future, I strongly encourage you to use the configureStore function from our Redux Starter Kit package, which detects mutations and will throw errors if you mutate.
I am trying to persist the state of Button option value in localStorage when the user selects it and retrieve the state in componentDidMount method but I am getting a null value. When the user navigates back to the page then state value should be there. Can anyone tell me what's wrong with my code?
code::
import React, { Component } from "react";
import { Button } from "semantic-ui-react";
import { withRouter } from "react-router";
import Answers from "../Answers/Answers";
class Section extends Component {
state = {
que1: "",
que2: "",
que3: ""
};
handleClick = event => {
this.setState(
{
que1: event.target.attributes.getNamedItem("data-key").value
}
),
() => {
localStorage.setItem("que1", que1);
console.log(this.state.que1);
}
};
handleClick2 = event => {
this.setState(
{
que2: event.target.attributes.getNamedItem("data-key").value
}
),
() => {
localStorage.setItem("que2", que2);
console.log(this.state.que2);
}
};
handleClick3 = event => {
this.setState(
{
que3: event.target.attributes.getNamedItem("data-key").value
}
),
() => {
localStorage.setItem("que3", que3);
console.log(this.state.que3);
}
};
componentDidMount() {
this.setState({
que1: localStorage.getItem("que1"),
que2: localStorage.getItem("que2"),
que3: localStorage.getItem("que3")
});
}
render() {
console.log(this.state);
let styles = {
width: '50%',
margin: '0 auto',
marginBottom: '15px'
}
const { history } = this.props;
const { que1, que2, que3 } = this.state;
return (
<>
<p>1. I was stressed with my nerves on edge.</p>
<Button.Group widths="5" onClick={this.handleClick} style={styles}>
<Answers selected={this.state.que1} style={{ backgroundColor: 'red' }} />
</Button.Group>
{` `}
<p>2. I lost hope and wanted to give up when something went wrong.</p>
<Button.Group widths="5" onClick={this.handleClick2} style={styles}>
<Answers selected={this.state.que2} style={{ backgroundColor: 'red' }} />
</Button.Group>
{` `}
<p>3. I feel very satisfied with the way I look and act</p>
<Button.Group widths="5" onClick={this.handleClick3} style={styles}>
<Answers selected={this.state.que3} style={{ backgroundColor: 'red' }} />
</Button.Group>
<p />
{` `}
<Button
disabled={!que1 || !que2 || !que3}
onClick={() => history.push("/section2", [this.state])}
>
NEXT
</Button>
</>
);
}
}
export default withRouter(Section);
output ::
In your onclick handlers, you have:
handleClick2 = event => {
this.setState(
{
que2: event.target.attributes.getNamedItem("data-key").value
}
),
() => {
localStorage.setItem("que2", que2);
console.log(this.state.que2);
}
};
In the setState callback, you need to change it to(you logged the correct value, but didn't store it properly):
localStorage.setItem("que2", this.state.que2);
This is not supposed to be the React way of doing it. You should implement a redux workflow here which will help you persist data when navigating between pages. Refer https://redux.js.org/basics/usage-with-react. And when you click on the back button, you can retrieve the values back from the redux store.
Now, in your case change it to
handleClick(e) => {
const value = event.target.attributes.getNamedItem('data-key').value;
this.setState({que1 : value});
localStorage.setItem('que1', value);
};
And in the constructor
constructor() {
this.state = {
que1 : localStorage.getItem('que1') ? localStorage.getItem('que1') : ''
};
};
But this above solution is not at all recommended. Go ahead with the redux approach.