I tried to solve this js react problem and get stuck on questions 2-4.
Question 2: I don't know how to check the local state for each row in order to check for the duplicate rank select
Question 3: Should I need props passed to the component to check for unique?
Question 4: How do I check all rows have a select ranked and unique?
Here are the questions:
Adding a class of "done" to a row will highlight it green. Provide this
visual feedback on rows which have a selected rank.
Adding a class of "error" to a row will highlight it red. Provide this
visual feedback on rows which have duplicate ranks selected.
There is a place to display an error message near the submit button. Show
this error message: Ranks must be unique whenever the user has selected the
same rank on multiple rows.
The submit button is disabled by default. Enable it when all rows have a
rank selected and all selected ranks are unique.
The orginal App.js
import React, { Component } from 'react';
import './App.css';
import MainPage from './components/MainPage';
class App extends Component {
render() {
return (
<MainPage />
);
}
}
export default App;
MainPage.js
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" />
</div>
);
}
}
export default MainPage;
FormRow.jsx
import React from 'react';
import _ from 'lodash';
class FormRow extends React.Component {
render() {
const cells = _.range(1, 6).map((i) => {
return (
<td key={`${this.props.animalName}-${i}`}>
<input
type="radio"
name={this.props.animalName}
value={i}
/>
</td>
);
});
return (
<tr>
<th>{this.props.animalName}</th>
{cells}
</tr>
)
}
}
export default FormRow;
Animal.js
class Animal {
constructor(name, rank) {
this.name = name;
this.rank = rank;
}
}
export default Animal;
My code is at GitHub (git#github.com:HuydDo/js_react_problem-.git). Thanks for your suggestion!
FormRow.jsx
import React from 'react';
import _ from 'lodash';
class FormRow extends React.Component {
constructor(){
super();
this.state = {
rowColor : false,
name: "",
rank: 0
// panda: 0,
// cat: 0,
// capybara: 0,
// iguana: 0,
// muskrat: 0
}
}
handleChange = (e) => {
if (this.state.rank === e.target.value){
console.log("can't select same rank.")
}
console.log(e.target.name)
console.log(e.target.value)
this.setState({
// [e.target.name]: e.target.value,
name: e.target.name,
rank: e.target.value,
rowColor: true
}, console.log(this.state))
}
handleChange2 = (e) => {
let newName = e.target.name
let newRank = e.target.value
let cRank = this.state.rank
let cName = this.state.name
console.log(this.state)
console.log(`${newRank} ${newName}`)
if(cName !== newName) {
if(cRank !== newRank) {
this.setState({
name : newName,
rank: newRank,
rowColor: true
},()=> console.log(this.state))
}
else {
console.log("can't select same rank")
}
}
// this.setState(previousState => {
// let cRank = previousState.rank
// let cName = previousState.name
// console.log(previousState)
// return {
// rank: newRank,
// name: newName,
// rowColor: true
// }
// },console.log(this.state.rank))
}
render() {
const cells = _.range(1, 6).map((i) => {
return (
<td key={`${this.props.animalName}-${i}`} onChange={this.handleChange2}>
<input
type="radio"
name={this.props.animalName}
value={i}
/>
</td>
);
});
return (
<tr className = {(this.state.rowColor) ? 'done':null} >
{/* <tr> */}
<th>{this.props.animalName}</th>
{cells}
</tr>
)
}
}
export default FormRow;
MainPage.jsx
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
getValue = ({name,rank}) =>{
console.log(`Name: ${name} rank: ${rank}`)
}
// handleSubmit = event => {
// event.preventDefault()
// this.props.getValue(this.state)
// }
checkForUnique = () => {
// Show this error message: `Ranks must be unique` whenever the user has selected the
// same rank on multiple rows.
this.setState({
error : "Ranks must be unique"
})
}
isDisabled = () =>{
// The submit button is disabled by default. Enable it when all rows have a
// rank selected and all selected ranks are unique.
return true
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
rank={animal.rank}
handleChange={this.handleChange}
getValue={this.getValue}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
{/* <form onSubmit={this.onSubmit}> */}
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" value="Submit" disabled={this.isDisabled()} /> {/* <button type="submit">Submit</button> */}
{/* </form> */}
</div>
);
}
}
export default MainPage;
enter image description here
I tried to add handleChange and handleAnimalSelect methods, but I get an error. The new name and rank are not added to the arrays.
MainPage.jsx
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
isDisabled = () =>{
// The submit button is disabled by default. Enable it when all rows have a
// rank selected and all selected ranks are unique.
return true
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
rank={animal.rank}
getValue={this.getValue}
handleAnimalSelect={this.handleAnimalSelect}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
{/* <form onSubmit={this.onSubmit}> */}
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" value="Submit" disabled={this.isDisabled()} />
{/* <button type="submit">Submit</button> */}
{/* </form> */}
</div>
);
}
}
export default MainPage;
FormRow.jsx
import React from 'react';
import _ from 'lodash';
import FormRow from './FormRow.jsx';
import Animal from './Animal.js';
class MainPage extends React.Component {
constructor(props) {
super(props);
this.state = {
animals: ['panda','cat','capybara','iguana','muskrat'].map((name) => {
return new Animal(name);
}),
error: ''
};
}
isDisabled = () =>{
// The submit button is disabled by default. Enable it when all rows have a
// rank selected and all selected ranks are unique.
return true
}
render() {
const rows = this.state.animals.map((animal) => {
return (
<FormRow
animalName={animal.name}
key={animal.name}
rank={animal.rank}
getValue={this.getValue}
handleAnimalSelect={this.handleAnimalSelect}
/>
);
});
const headers = _.range(1, 6).map((i) => <th key={`header-${i}`}>{i}</th>);
return (
<div>
{/* <form onSubmit={this.onSubmit}> */}
<table>
<thead>
<tr>
<th></th>
{headers}
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
<div>{this.state.error}</div>
<input type="submit" value="Submit" disabled={this.isDisabled()} />
{/* <button type="submit">Submit</button> */}
{/* </form> */}
</div>
);
}
}
export default MainPage;
You're pretty much making a form with a few rows of multiple choice answers.
One way of simplifying everything is to have all the logic in the top component, in your case I think MainPage would be where it would be. Pass down a function as a prop to all the descendants that allows them to update the form data upstream.
In Q2, how do intend to check the state for each row? Perhaps you can use arrays or objects to keep track of the status of each question. The arrays/objects are stored in state, and you just check them to see what the status is.
I'm actually not clear what your app looks like - what does a row look like? (You might want to post a screenshot) And I don't see any way for rank to be selected - I don't even see what the ranks are for, or how they are used in the form. So perhaps your form design needs to be tweaked. You should begin the form design with a clear picture in YOUR mind about how the app will work. Maybe start by drawing the screens on paper and drawing little boxes that will represent the objects/array variables and go through the process of a user using your app. What happens to the various boxes when they click radio buttons and so on. How will you know if the same rank is selected twice - where are the selected ranks stored? What animals are clicked/selected? Where are those stored? Draw it all on paper first.
Array or objects: If you want to keep it simple, you can do the whole project just using arrays. You can have one array that stores all the animals. You can have a different array that stores which animals are selected right NOW (use .includes() to test if an animal is in that array). You can have another array that stores the rows that have a rank selected. When the number of elements in that row === the number of rows (is that the same as the number of animals? If yes, then you can use the length of the animals array for that test)
How do you know if the rows with a rank selected are unique? One way is to DISALLOW selected a rank that has already been selected. Again, use .includes() (e.g. arrSelectedRanks.includes(num)) to check if a rank has already been selected.
SO what do one of these checks look like?
const handleAnimalSelect = (animal) => {
const err = this.state.selectedAnimals.includes(animal);
if (err === true){
this.setState(error: animal);
}
}
return (
<input
type="radio"
name={this.props.animalName}
value={i}
onClick={this.handleAnimalSelect}
/>
{ error !== undefined && (
<div class={style.errorMessage}>{`Animal ${} was chosen twice`}</div>
)}
);
};
Remember: State is what you use for remembering the value of variables in a given component. Every component has its own state. But Props are for data/functions/elements that are passed into the component. You don't update the values of props in the component (prop values are stored in another component. If you need to update them, you use functions to pass data back to the parent component where that variable is in state, and update the value there).
Here is an example that uses .includes() to check for the presence/absence of something:
https://stackoverflow.com/a/64486351/1447509
Related
I am making a pos system and I am trying to make the items appear on the list section when I click on each of them. My problem is that the Items section and the List section are two different components and I can not figure out how to make a click in Items section change the state of the list section.
Items Section:
import Item from "./Item";
function ItemSection() {
const Items = [{ title: "DOMAIN", cost: 109 }];
return (
<div>
<Item title={Items[0].title} cost={Items[0].cost} onClick={() => this.clickHandler(title, cost)}></Item>
</div>
);
}
export default ItemSection;
List Section:
import React, { useState } from "react";
function ListItems(props) {
const [title, setTitle] = useState(props.title);
const [cost, setCost] = useState(props.cost);
const clickHandler = (mTitle, mCost) => {
setTitle(mTitle);
setCost(mCost);
};
return (
<div>
<table>
<tr>
<td> {title} </td>
<td> ${cost} </td>
</tr>
</table>
</div>
);
}
export default ListItems;
Item:
function Item(props) {
return (
<div>
<button>{props.title}</button>
</div>
);
}
export default Item;
As per my understanding, you've two components: ItemSection and ListItems and you want to call a function in ListItems, that is defined in ItemSection? Is it the correct understanding?
If yes, then you can define your function in ItemSection and send that function as prop in ItemSection
In ItemSection:
<ListItems sampleFunction = {(e)=>sampleFunction(e)}/>
In ListItems:
interface Props{
sampleFunction: Function;
}
and:
<button OnClick = {props.sampleFunction}>{props.title}</button>
This is just a pseudo code.
I have a table that has been created dynamically, and am attempting to put full CRUD capabilities onto it. For business reasons I am unable to use external libraries for this, and so have resulted in using basic HTML with react. I am currently trying to detect changes within the data. My problem is in regards to the onInput event with the div inside the tag. When the components are first initialized with the data, the onInput event fires for each one rather than waiting for an actual user input. To a degree I understand why this is happening, but I am in need of a workaround for it or an alternative. I have created a small demo below to show a mock of the current code:
Parent class:
import React, {Component} from 'react';
class FormContainer extends Component{
constructor(props){
super(props)
this.state={
rowData : myData
}
this.onInput = this.onInput.bind(this)
}
onInput = (rowKey) => {
console.log(rowKey)
}
render() {
return(
<Grid
data={this.state.rowData}
onInput={this.onInput}
/>
)
}
}
Grid class:
import React, {Component} from 'react';
class Grid extends Component{
constructor(props){
super(props)
}
render(){
let columns = [];
let rows = [];
if(this.props.data != null){
columns = this.props.data.slice(0, 1).map((row, i) => {
return(
Object.keys(row).map((column, key) => {
return(
<th key={key}>{column}</th>
)
})
)
})
rows = this.props.data.map((row, rowKey) => {
return(
<tr key={rowKey}>
{Object.keys(row).map((data, cellKey) => {
return(
<td key={cellKey} suppressContentEditableWarning="true" contentEditable="true" onChange={this.props.onInput(rowKey)}>{row[data]}</td>
)
})}
</tr>
)
})
}
return(
<table>
<thead><tr>{columns}</tr></thead>
<tbody>{rows}</tbody>
</table>
)
}
}
export default Grid;
The issue is that when your component is rendered any time, you are calling your onInputmethod:
<td
key={cellKey}
suppressContentEditableWarning="true"
contentEditable="true"
--> onChange={this.props.onInput(rowKey)}>{row[data]}</td>
Instead of calling it you have to pass the a function, in this case you can pass an anonymous function or an arrow function:
<td
key={cellKey}
suppressContentEditableWarning="true"
contentEditable="true"
--> onChange={ () => { this.props.onInput(rowKey); } }>{row[data]}</td>
Im making my first react project. Im new in JS, HTML, CSS and even web app programming.
What i want to do it is a Search input label. Now its look like this:
Like you can see i have some list of objects and text input.
I Have two components, my ProjectList.js with Search.js component...
class ProjectsList extends Component {
render() {
return (
<div>
<Search projects={this.props.projects} />
<ListGroup>
{this.props.projects.map(project => {
return <Project project={project} key={project.id} />;
})}
</ListGroup>
</div>
);
}
}
export default ProjectsList;
... and ProjectList.js displays Project.js:
How looks Search.js (its not ended component)
class Search extends Component {
state = {
query: ""
};
handleInputChange = () => {
this.setState({
query: this.search.value
});
};
render() {
return (
<form>
<input
ref={input => (this.search = input)}
onChange={this.handleInputChange}
/>
<p />
</form>
);
}
}
export default Search;
My project have name property. Could you tell me how to code Search.js component poperly, to change displaying projects dynamically based on input in text label? for example, return Project only, if text from input match (i want to search it dynamically, when i start typing m... it shows all projects started on m etc).
How to make that Search input properly? How to make it to be universal, for example to Search in another list of objects? And how to get input from Search back to Parent component?
For now, in react dev tools whatever i type there i get length: 0
Thanks for any advices!
EDIT:
If needed, my Project.js component:
class Project extends Component {
state = {
showDetails: false
};
constructor(props) {
super(props);
this.state = {
showDetails: false
};
}
toggleShowProjects = () => {
this.setState(prevState => ({
showDetails: !prevState.showDetails
}));
};
render() {
return (
<ButtonToolbar>
<ListGroupItem className="spread">
{this.props.project.name}
</ListGroupItem>
<Button onClick={this.toggleShowProjects} bsStyle="primary">
Details
</Button>
{this.state.showDetails && (
<ProjectDetails project={this.props.project} />
)}
</ButtonToolbar>
);
}
}
export default Project;
To create a "generic" search box, perhaps you could do something like the following:
class Search extends React.Component {
componentDidMount() {
const { projects, filterProject, onUpdateProjects } = this.props;
onUpdateProjects(projects);
}
handleInputChange = (event) => {
const query = event.currentTarget.value;
const { projects, filterProject, onUpdateProjects } = this.props;
const filteredProjects = projects.filter(project => !query || filterProject(query, project));
onUpdateProjects(filteredProjects);
};
render() {
return (
<form>
<input onChange={this.handleInputChange} />
</form>
);
}
}
This revised version of Search takes some additional props which allows it to be reused as required. In addition to the projects prop, you also pass filterProject and onUpdateProjects callbacks which are provided by calling code. The filterProject callback allows you to provide custom filtering logic for each <Search/> component rendered. The onUpdateProjects callback basically returns the "filtered list" of projects, suitable for rendering in the parent component (ie <ProjectList/>).
The only other significant change here is the addition of visibleProjects to the state of <ProjectList/> which tracks the visible (ie filtered) projects from the original list of projects passed to <ProjectList/>:
class Project extends React.Component {
render() {
return (
<div>{ this.props.project }</div>
);
}
}
class ProjectsList extends React.Component {
componentWillMount() {
this.setState({ visibleProjects : [] })
}
render() {
return (
<div>
<Search projects={this.props.projects} filterProject={ (query,project) => (project == query) } onUpdateProjects={ projects => this.setState({ visibleProjects : projects }) } />
<div>
{this.state.visibleProjects.map(project => {
return <Project project={project} key={project.id} />;
})}
</div>
</div>
);
}
}
class Search extends React.Component {
componentDidMount() {
const { projects, filterProject, onUpdateProjects } = this.props;
onUpdateProjects(projects);
}
handleInputChange = (event) => {
const query = event.currentTarget.value;
const { projects, filterProject, onUpdateProjects } = this.props;
const filteredProjects = projects.filter(project => !query || filterProject(query, project));
onUpdateProjects(filteredProjects);
};
render() {
return (
<form>
<input onChange={this.handleInputChange} />
</form>
);
}
}
ReactDOM.render(
<ProjectsList projects={[0,1,2,3]} />,
document.getElementById('react')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.0.0/umd/react-dom.production.min.js"></script>
<div id="react"></div>
I will assumes both your Search and ProjectList component have a common parent that contains the list of your projects.
If so, you should pass a function into your Search component props, your Search component will then call this function when the user typed something in the search bar. This will help your parent element decide what your ProjectsLists needs to render :
handleInputChange = () => {
this.props.userSearchInput(this.search.value);
this.setState({
query: this.search.value
});
};
And now, here is what the parent element needs to include :
searchChanged = searchString => {
const filteredProjects = this.state.projects.filter(project => project.name.includes(searchString))
this.setState({ filteredProjects })
}
With this function, you will filter out the projects that includes the string the user typed in their names, you will then only need to put this array in your state and pass it to your ProjectsList component props
You can find the documentation of the String includes function here
You can now add this function to the props of your Search component when creating it :
<Search userSearchInput={searchChanged}/>
And pass the filtered array into your ProjectsList props :
<ProjectsList projects={this.state.filteredProjects}/>
Side note : Try to avoid using refs, the onCHnage function will send an "event" object to your function, containing everything about what the user typed :
handleInputChange = event => {
const { value } = event.target
this.props.userSearchInput(value);
this.setState({
query: value
});
};
You can now remove the ref from your code
I am learning reactJS and so I am trying my hands on an example. This example has a form textfield that can add an item to an existing array on click of a button. I am having errors here as when I enter a text and click on the button, the array list is not updated except I try to make changes to the text entered in the textfield. This is what I am doing:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
currentName : '',
arrays : ['john', 'james', 'timothy']
}
}
render() {
const showNames = this.state.arrays.map((thisName) => {
const values = <li>{thisName}</li>;
return values;
});
const getText = (e) => {
let value = e.target.value;
this.setState({
currentName : value
})
}
const addToUsers = () => {
this.state.arrays.push(this.state.currentName)
}
return (
<div>
<p>Add new name to List</p><br/>
<form>
<input type="text" onChange={getText}/>
<button type="button" onClick={addToUsers}>Add User</button>
</form>
<ul>
{showNames}
</ul>
</div>
);
}
}
export default App;
There are a host of things wrong with this, but your issue is likely that you need to use setState to modify state.
import React, { Component } from 'react';
class App extends Component {
constructor(){
super();
this.state = {
names: ['john', 'james', 'timothy']
}
}
addToUsers = () => {
this.setState(
prevState => ({
names: [...prevState.names, this.input.value]
})
)
}
render() {
const names = this.state.names.map(
(name, index) => <li key={index}>{name}</li>
)
return (
<div>
<p>Add new name to List</p><br/>
<form>
<input type="text" ref={e => this.input = e} />
<button type="button" onClick={this.addToUsers}>Add User</button>
</form>
<ul>
{names}
</ul>
</div>
)
}
}
export default App;
This quick edit changes a few things:
Uses setState for the addToUsers method
Eliminate onChange tracking and pull the name directly from the input when the button is clicked
Move the addToUsers method out to the component class rather than defining it on render
Rename this.state.arrays to this.state.names
Simplify conversion of this.state.names into list items
Set key on array elements (name list items)
Use prevState in setState to avoid race conditions
You need to make sure you update state using the setState method.
When you update arrays you are reaching into the state object and manipulating the data directly instead of using the method.
Instead try something like:
const addToUsers = () => {
const newArray = this.state.arrays.concat([this.state.currentName]);
this.setState({
arrays: newArray
});
}
You probably must add
onChange={getText}.bind(this)
to your functions.
Also change this
const addToUsers = () => {
this.state.arrays.push(this.state.currentName)
}
to this
const addToUsers = () => {
this.setState({here put your variable})
}
I have a shopping list app that is divided to two components as follows:
I implemented those two components as: ShoppingList and:ItemDetails
There is another component: ListItem that represents one item row (with edit and delete buttons).
ShoppinList maps over an array of ListItems.
My App component fetches an initial items array and sends it to ShoppingList.
Each time a click is made on the edit icon in a specific item row I set selectedItem object in my app component and render the ItemDetails component, passing it the selectedItem like so:
toggleDetailsPanel = (itemId) => (e) => {
this.setState((prevState, props) => {
return {
selectedItem: (prevState.selectedItem && prevState.selectedItem.id === itemId) ? null : this.findItemById(itemId),
};
});
};
And in the App render function I render it like that:
<div className={styles.details_outer_container}>
{this.state.selectedItem ? <ItemDetails handleSubmit={this.saveDetails} item={this.state.selectedItem}/> : null}
</div>
Whenever a click is made on the save button I run a function on the app component that updates the item in the items array (saveDetails).
Now I expected the ItemDetails component to render with new values each time I click on a different edit icon in a different item row, but the inputs values won't change, only the title is rendering.
I tried all solutions that I found, involving defaultValue, or setting value with getValue() function, or setting a dynamic key on the inputs, but nothing really helps.
This is my ItemDetails file:
import React from 'react';
import PropTypes from 'prop-types';
import { Grid, Row, Col, input, Button } from 'react-bootstrap';
import styles from './styles.css';
export default class ProductDetails extends React.Component {
static propTypes = {
handleSubmit: PropTypes.func.isRequired,
item: PropTypes.any.isRequired,
};
state = {
id: this.props.item.id,
name: this.props.item.name,
quantity: this.props.item.quantity,
price: this.props.item.price,
description: this.props.item.description,
};
// Set appropriate property in state by input name
handleInputChange = (e) => {
this.setState({
[e.target.name]: e.target.value,
});
};
// Submit changed item to parent component
handleDetailsSubmit = (e) => {
this.props.handleSubmit(this.state);
e.preventDefault();
};
render() {
const item = this.props.item;
const itemName = item.name.toUpperCase() || '';
return (
<div className={styles.details_container}>
<div className="sub_header">
<span>{`${itemName} DETAILS`}</span>
</div>
<form className={styles.form_style}>
<p>
<label>{'Quantity'}</label>
<input type="text" ref="quantity" name="quantity" value={this.state.quantity} onChange={this.handleInputChange} />
</p>
<p>
<label>{'Price'}</label>
<input type="text" ref="price" name="price" value={this.state.price} onChange={this.handleInputChange}/>
</p>
<p>
<label>{'Description'}</label>
<textarea rows={2} ref="description" name="description" value={this.state.description} onChange={this.handleInputChange}/>
</p>
<div className={styles.button_div}>
<Button onClick={this.handleDetailsSubmit} bsStyle="primary" bsSize="small">
{'Save'}
</Button>
</div>
</form>
</`enter code here`div>
);
}
}
I understand this is React's way of handling forms but really don't know how to solve it.
I would really appreciate any help : )
The ProductDetails component only gets its initial values from item. From that point it is all maintained in state. So you need to reset the state when item changes.
Try adding something like this:
componentWillReceiveProps( newProps ) {
if ( this.props.item !== newProps.item ) {
this.setState( {
id: newProps.item.id,
name: newProps.item.name,
quantity: newProps.item.quantity,
price: newProps.item.price,
description: newProps.item.description,
} )
}
}