Updating & appending to React array state - javascript

I have a form where users create a coding problem. In the form, there is the option to add sample test cases via input and output text boxes. The user can click a button to add a new test case. Right now I have a state object that holds all of the form data, formObj, and within it is a sample_test_cases field which I want to hold an array of objects, like: [{ input: "", output: "" }].
The issue I am having is updating this array. I need to be able to concat a new object to it each time a test case is added. Then updating the state at that index when the text box is changed. I have tried creating a stateless array and updating it, then setting sample_test_cases to that array. This is not working, however.
Here is a sandbox with my code: https://codesandbox.io/s/eloquent-snowflake-n4bpl?file=/src/AddProblemForm.js
If anyone could give me tips that would really help. I'm not too familiar with Javascript or complex state management. Thanks.

See snippet below (I'm having issues with saving the sandbox). A few issues that it addresses:
You also kept track of state using some local arr variable; updating that won't trigger a re-render, so you'll need to modify the sample_test_cases array inside your formObj state.
The textarea value should also be reflecting what is in your state. To make this more convenient, I've passed the test case into the SampleTestCase component as a prop, so it will react to state changes.
React state should be treated as immutable. So when the input text box is updated, you should set the state to a new object with a new sample_test_cases array, which is constructed of the first i-1 test cases, a new ith test case with modified input, and the remaining test cases.
Move SampleTestCase outside of the AddProblemForm component. If you don't, you will find that whenever the input textarea is changed, you will lose keyboard focus. This is because the SampleTestCase component is being redefined on each render, which is triggered by a state change. (Similar problem: React.js - input losing focus when rerendering)
import React, { useState } from "react";
import { Form, Button, Col } from "react-bootstrap";
import { BsPlusSquare } from "react-icons/bs";
const SampleTestCase = ({ testCase, updateInput }) => {
return (
<Form.Row>
<Col>
<Form.Group controlId="input">
<Form.Label>Sample Input</Form.Label>
<Form.Control
required
as="textarea"
rows={2}
onChange={updateInput}
value={testCase.input}
/>
</Form.Group>
</Col>
<Col>
<Form.Group controlId="output">
<Form.Label>Sample Output</Form.Label>
<Form.Control
required
as="textarea"
rows={2}
// onChange={(event) =>
// setFormObj({
// ...formObj,
// sample_test_cases: {
// ...formObj.sample_test_cases,
// output: event.target.value
// }
// })
// }
/>
</Form.Group>
</Col>
</Form.Row>
);
};
const AddProblemForm = () => {
const [formObj, setFormObj] = useState({
sample_test_cases: [{ input: "", output: "" }]
// other state obj info
});
const AddSampleTestCase = () => {
// make new instance!
const newTestCase = { input: "", output: "" };
setFormObj({
...formObj,
sample_test_cases: [...formObj.sample_test_cases, newTestCase]
});
};
console.log(formObj);
const updateInputFor = (i) => (event) => {
event.preventDefault();
const { sample_test_cases } = formObj;
const testCase = sample_test_cases[i];
testCase.input = event.target.value;
setFormObj({
...formObj,
sample_test_cases: [
...sample_test_cases.slice(0, i),
testCase,
...sample_test_cases.slice(i + 1)
]
});
};
return (
<div>
Problem Form
<Form>
<h5 style={{ paddingTop: "1rem" }}>Sample Test Cases</h5>
{formObj.sample_test_cases.map((testCase, i) => (
<React.Fragment key={i}>
<SampleTestCase
key={i}
testCase={testCase}
updateInput={updateInputFor(i)}
/>
<hr />
</React.Fragment>
))}
<Button onClick={AddSampleTestCase}>
<div>Add Sample Test Case</div>
</Button>
</Form>
</div>
);
};
export default AddProblemForm;

I suggest you use useReducer hook in cases your state is complicated.
hooks API
useReducer is usually preferable to useState when you have complex
state logic that involves multiple sub-values or when the next state
depends on the previous one.
AddProblemForm.js:
import React, { useReducer } from "react";
import { Form, Button, Col } from "react-bootstrap";
import { BsPlusSquare } from "react-icons/bs";
import SampleTestCase from "./SampleTestCase";
const initialState = {
sample_test_cases: [],
counter: 0
// other state obj info
};
function reducer(state, action) {
switch (action.type) {
case "addSampleTestCase": {
const { data } = action;
return {
...state,
sample_test_cases: [...state.sample_test_cases, data],
counter: state.counter + 1
};
}
case "updateTest": {
const { index, value } = action;
return {
...state,
sample_test_cases: state.sample_test_cases.map((item, i) => {
if (i === index) {
return value;
} else {
return item;
}
})
};
}
default:
throw new Error();
}
}
const AddProblemForm = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const AddSampleTestCase = () => {
dispatch({ type: "addSampleTestCase", data: { input: "", output: "" } });
};
/* console.log(state); */
return (
<div>
Problem Form
<Form>
<h5 style={{ paddingTop: "1rem" }}>Sample Test Cases</h5>
{state.sample_test_cases.map((sample_test_case, i) => (
<div key={i}>
<SampleTestCase
sample_test_case={sample_test_case}
updateValue={(value) =>
dispatch({ type: "updateTest", index: i, value })
}
/>
<hr />
</div>
))}
<Button onClick={AddSampleTestCase}>
<div>Add Sample Test Case</div>
</Button>
</Form>
</div>
);
};
export default AddProblemForm;
SampleTestCase.js:
import React from "react";
import { Form, Button, Col } from "react-bootstrap";
const SampleTestCase = ({ sample_test_case, updateValue }) => {
return (
<Form.Row>
<Col>
<Form.Group controlId="input">
<Form.Label>Sample Input</Form.Label>
<Form.Control
required
as="textarea"
rows={2}
value={sample_test_case.input}
onChange={(event) => updateValue(event.target.value)}
/>
</Form.Group>
</Col>
<Col>
<Form.Group controlId="output">
<Form.Label>Sample Output</Form.Label>
<Form.Control
required
as="textarea"
rows={2}
value={sample_test_case.output}
onChange={(event) => updateValue(event.target.value)}
/>
</Form.Group>
</Col>
</Form.Row>
);
};
export default SampleTestCase;

Related

React.js updates some part of DOM nodes when I'm deleting only one element

As I know React creates a new Virtual DOM and compares it with previous one, then it updates Browser DOM with least number of changes possible without rendering the entire DOM again. (in short)
In React documentation I have also read how key should work.
for demonstrating this, I have created todo app, but when I'm deleting one element, all previous elements are re-rendered again (except if I'm not deleting recently added element)
Here is screenshot:
(In Chrome developer tool paint flashing is active for showing renders)
My questions:
Why do previous elements re-render again?
Why key could not fix this problem?
Here is the entire code:
TodoApp.jsx
import React, { useState } from 'react';
import Input from './Input';
import List from './List';
const TodoApp = () => {
const [inputText, setInputText] = useState('');
const [todos, setTodos] = useState([]);
const onSubmitChange = e => {
e.preventDefault();
setTodos([
...todos,
{ text: inputText, completed: false, id: Math.random() * 1000 },
]);
setInputText('');
};
const onChangeEvent = e => {
setInputText(e.target.value);
};
return (
<div>
{todos.map(todo => {
return (
<List todos={todos} setTodos={setTodos} todo={todo} key={todo.id} />
);
})}
<Input
onSubmit={onSubmitChange}
onChange={onChangeEvent}
inputText={inputText}
/>
</div>
);
};
export default TodoApp;
List.jsx
import React from 'react';
import "../todolist/css/TodoApp.css"
const List = ({ todo, todos, setTodos }) => {
const deleteHandle = () => {
setTodos(todos.filter(el => el.id !== todo.id));
};
const completeHandle = () => {
setTodos(
todos.map(el => {
if (el.id === todo.id) {
return { ...el, completed: !el.completed };
}
return el;
})
);
};
return (
<div className={`${todo.completed ? 'completed' : ''}`}>
<div>{todo.text}</div>
<div className="btns">
<button onClick={deleteHandle} className="btn btn-delete">
Delete
</button>
<button onClick={completeHandle} className="btn btn-complete">
complete
</button>
</div>
</div>
);
};
export default List;
Input.jsx
import React from 'react';
const Input = ({ onSubmit, onChange, inputText }) => {
return (
<form onSubmit={onSubmit}>
<input
onChange={onChange}
value={inputText}
type="text"
name="myInput"
autoComplete="off"
/>
</form>
);
};
export default Input;

React Form not updating state onChange

I'm trying to practice React forms, and I can't seem to solve this error. I've developed a multi-input form and I need the value to update the parent's state. When I start typing in the input field it triggers the Switch case default. I'm not sure if maybe I'm typing the 'handleChange' function wrong or if I should have a separate state for the state.data. Any advice would be much appreciated
import React, { useState } from 'react';
import Form from './Form';
import Results from './Results';
function App() {
const [state, setState] = useState({
data: 1,
Name: '',
Email: '',
City: ''
});
const nextStep = () => {
setState({
data: state.data + 1
});
};
const handleChange = e => {
let field = e.target.name;
let val = e.target.value;
setState({ [field]: val });
};
switch (state.data) {
case 1:
return (
<div className='App-container'>
<Form
button='Next'
nextStep={nextStep}
name='Name'
state={state.name}
handleChange={handleChange}
/>
</div>
);
case 2:
return (
<div className='App-container'>
<Form
button='Next'
nextStep={nextStep}
name='Email'
state={state.email}
handleChange={handleChange}
/>
</div>
);
case 3:
return (
<div className='App-container'>
<Form
button='Submit'
nextStep={nextStep}
name='City'
state={state.city}
handleChange={handleChange}
/>
</div>
);
case 4:
return (
<div className='App-container'>
<Results data={state} />
</div>
);
default:
return 'Error';
}
}
export default App;
import React from 'react';
const Form = ({ button, nextStep, name, state, handleChange }) => {
const handleSubmit = e => {
e.preventDefault();
nextStep();
};
return (
<div className='Form-container'>
<form onSubmit={handleSubmit}>
<input
type='text'
placeholder={name}
name={name}
value={state}
onChange={handleChange}
/>
<input type='submit' value={button} />
</form>
</div>
);
};
export default Form;
import React from 'react';
const Results = ({ data }) => {
return (
<div>
<h1>Info</h1>
<p>{data.name}</p>
<p>{data.email}</p>
<p>{data.city}</p>
</div>
);
};
export default Results;
You losing state on handleChange while expecting it to merge with the current one, but it is not how useState works in contradiction to this.setState in class components:
// Results new state: { data };
setState({ data: state.data + 1 });
// Instead update the copy of the state.
// Results new state: { data, Name, Email, City }
setState({ ...state, data: state.data + 1 });
Check useState note in docs:
Note
Unlike the setState method found in class components, useState does
not automatically merge update objects. You can replicate this
behavior by combining the function updater form with object spread
syntax.
Another option is useReducer,
which is more suited for managing state objects that contain multiple
sub-values.
I recommend using a custom hook for form inputs.like follows
//useForm.js
const useForm = defaultValues => {
const [values, setValues] = useState(defaultValues);
const handleChange = ({ name, value }) => {
setValues(prevState => ({ ...values, [name]: value }));
};
const reset = () => {
setValues(null);
};
return [values, handleChange, reset];
};
inside component
const [formValues, handleChange, resetForm] = useForm();
return (
<>
<Input
value={formValues.name}
onChange: str => handleChange({ name: "name", value: str })
/>
<Input
value={formValues.email}
onChange: str => handleChange({ name: "email", value: str })
/>
</>
)
You need to spared old state
const handleChange = e => {
let field = e.target.name;
let val = e.target.value;
setState({ ...state, [field]: val });
};
this is setState({ ...state, [field]: val });

React rendering deleted array element after setState()

I'm having an issue where React seems to be rendering a deleted array element after I've removed it from an array in the components state. After setState(), rendering is triggered, but the deleted item is shown, instead of the remaining item (see GIF video below).
Although the component is extremely simple and I've spent hours on this problem, I haven't been able to solve this issue. The strange thing is that the newState object actually contains the valid new list, but it's not rendered.
I really hope someone can help me figure this out!
import React from "react";
import Button from "#material-ui/core/Button";
import update from "immutability-helper";
import Grid from "#material-ui/core/Grid";
import TextField from "#material-ui/core/TextField";
import * as R from "ramda";
class SessionNoteGroup extends React.Component {
state = {
id: this.props.id,
notes: this.props.notes
};
render() {
const { classes } = this.props;
const { id, notes } = this.state;
return (
<div>
<Grid container>
<Grid item xs={12}>
<TextField
multiline
fullWidth
id="notes"
name="notes"
label="Notes"
rows="2"
value={notes}
onChange={this.handleValueChange}
/>
</Grid>
</Grid>
<Button variant="outlined" color="primary" onClick={this.handleDelete}>
Delete
</Button>
</div>
);
}
handleValueChange = event => {
const { name, value } = event.target;
const { id, notes } = this.state;
let newState = {
id: id,
notes: value
};
this.setState(newState);
};
handleDelete = () => {
this.props.onDelete(this.state.id);
};
}
class SessionNotes extends React.Component {
state = {
notes: this.props.notes.slice(),
deleted: []
};
next_id = 2;
createNotes = () => {
let notesList = [];
for (let i = 0; i < this.state.notes.length; i++) {
const { id, notes } = this.state.notes[i];
notesList.push(
<SessionNoteGroup
id={id}
notes={notes}
onDelete={this.handleDelete}
index={i + 1}
/>
);
}
console.log(notesList);
return notesList;
};
handleDelete = id => {
const newNotes = R.filter(note => note.id !== id, this.state.notes);
this.setState({ notes: newNotes });
};
handleClickAdd = async () => {
const note = {
id: this.next_id,
notes: ""
};
this.next_id++;
const newState = update(this.state, { notes: { $push: [note] } });
this.setState(newState);
};
render() {
return (
<div>
{this.createNotes()}
<Button
variant="outlined"
color="primary"
onClick={this.handleClickAdd}
>
Add
</Button>
</div>
);
}
}
export default SessionNotes;
Few things.
When you want to set the state, based on the prev state, use the setState with a callback, which takes as argument the prevState. So the next code:
handleValueChange = event => {
const { name, value } = event.target;
const { id, notes } = this.state;
let newState = {
id: id,
notes: value
};
this.setState(newState);
};
Will be something like:
handleValueChange = event => {
const { name, value } = event.target;
const { id, notes } = this.state;
this.setState(prevState => ({ id: prevState.id, notes: value}));
};
Same in the below component:
handleDelete = id => {
const newNotes = ;
this.setState(prevState => ({ notes: R.filter(note => note.id !== id, prevState.notes) }));
};
And so on for all the times that you update the state based on previous state value.
Then when you do create a list of elements in react, use key property:
<SessionNoteGroup
key={id}
id={id}
notes={notes}
onDelete={this.handleDelete}
index={i + 1}
/>
That's used by react for managing the render of list of items
Try adding a key to the container div of your render
return (
<div key = {this.props.id}>
<Grid container>
<Grid item xs={12}>
<TextField
multiline
fullWidth
id="notes"
name="notes"
label="Notes"
rows="2"
value={notes}
onChange={this.handleValueChange}
/>
</Grid>
</Grid>
<Button variant="outlined" color="primary" onClick={this.handleDelete}>
Delete
</Button>
</div>
);

Redux Form refuses to update

it seems that i am unable to get the form to rerender on each keystroke. I must be doing something wrong I just cannot tell what it is. The GetStartedForm function never runs twice, and neither does the function that contains the Field input.
use of redux form
const GetStartedForm = (props) => {
const {
handleSubmit,
pristine
} = props;
return (
<Form onSubmit={handleSubmit}>
<Field
name="email"
component={FormField}
type="text"
size="xl"
placeholder="Email Address"
autoComplete="email"
validate={[required(), email()]}
/>
<Button
disabled={pristine}>Get Started</Button>
</Form>
);
}
export default reduxForm({ form: 'getstarted' })(GetStartedForm);
implementation
<GetStarted onSubmit={e => {
console.log(e);
}} />
input field
const TextField = props => {
const { input, meta, size } = props;
console.log(props);
const properties = meta.uncontrolled ? {
defaultValue: props.defaultValue
} : {
value: input.value
};
return (
<React.Fragment>
{props.label && (
<label htmlFor={input.name} className="form__label">
{props.label}
{props.required ? ' *' : null}
</label>
)}
<Input
type={props.type ? props.type : 'text'}
className={props.className}
name={input.name}
id={input.name}
size={props.size}
readOnly={props.readOnly}
onChange={input.onChange}
autoFocus={props.autoFocus}
autoComplete={props.autoComplete}
placeholder={props.placeholder}
{...properties}
/>
{meta.touched && meta.error ? (
<div className="form__field-error">{meta.error}</div>
) : null}
</React.Fragment>
);
};
when i pass in uncontrolled like this i am able to get the text to at least show up on my screen, but i seem to be unable to get the form function to run again, which means that my button is stuck at disabled (pristine)
<Field
name="email"
component={FormField}
type="text"
size="xl"
placeholder="Email Address"
autoComplete="email"
validate={[required(), email()]}
meta={{uncontrolled: true}}
/>
yes reducers are set up
/**
* Combine all reducers in this file and export the combined reducers.
*/
import { fromJS } from 'immutable';
import { combineReducers } from 'redux-immutable';
import { LOCATION_CHANGE } from 'react-router-redux';
import { reducer as formReducer } from 'redux-form';
import {
LOGOUT_USER_REQUEST
} from 'constants'
import globalReducer from 'containers/App/reducer';
import languageProviderReducer from 'containers/LanguageProvider/reducer';
/*
* routeReducer
*
* The reducer merges route location changes into our immutable state.
* The change is necessitated by moving to react-router-redux#5
*
*/
// Initial routing state
const routeInitialState = fromJS({
location: null,
});
/**
* Merge route into the global application state
*/
function routeReducer(state = routeInitialState, action) {
switch (action.type) {
/* istanbul ignore next */
case LOCATION_CHANGE:
return state.merge({
location: action.payload,
});
default:
return state;
}
}
/**
* Creates the main reducer with the dynamically injected ones
*/
export default function createReducer(injectedReducers) {
const composite = combineReducers({
route: routeReducer,
global: globalReducer,
language: languageProviderReducer,
form: formReducer,
...injectedReducers,
});
return rootReducer;
function rootReducer(state_, action) {
let state = state_;
if (action.type === LOGOUT_USER_REQUEST) {
state = null;
}
return composite(state, action);
}
}
I just realized that this react boilerplate uses immutable as its base so i had to import redux-form/immutable everywhere i was using redux-form

React Redux Redux Form - moving a function from within a <Field> produces error

Novice.
I have a class Address which I ultimately want to split into a presentational component and container. It all works as is but when I move this particular function outside the render function from initially within the actual async.select form field -
onSuburbChange = (value) => {
this.setState({ selectedSuburb: value }, () => {
input.onChange(value)
updatePostcodeValue(value ? value.postcode : null, sectionPrefix)
})
}
...I find I am getting hit with a number of errors based on the the fact that they are unreferenced.
The error I get is
address.jsx:56 Uncaught ReferenceError: input is not defined
If I comment this line out I get the same type of error on updatePostcodeValue.
Here is the entire address file. As you can see it would be good to move the presentational section in render off to another file but I need to move all the functions to the outside of the render function.
NOTE: I have commented out where the function orginal sat so anybody who has a crack at this question knows where it was and also where I intended to move it...
import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'
import { Field, change } from 'redux-form'
import { Col, Panel, Row } from 'react-bootstrap'
import Select from 'react-select'
import { getSuburbs } from './actions'
import FormField from '../formComponents/formField'
import TextField from '../formComponents/textField'
import StaticText from '../formComponents/staticText'
import { CLIENT_FORM_NAME } from '../clients/client/client'
export class Address extends Component {
static contextTypes = {
_reduxForm: PropTypes.object.isRequired,
}
constructor(props, context) {
super(props, context)
this.state = {
selectedSuburb: null,
}
}
// Manage Select for new data request - for suburbs.
handleSuburbSearch = (query) => {
console.group('handleSuburbSearch')
console.log('query', query)
const { addressData } = this.props
console.log('addressData', addressData)
const companyStateId = addressData.companyStateId
console.log('companyStateId', companyStateId)
if (!query || query.trim().length < 2) {
console.log('no query; bailing!')
console.groupEnd()
return Promise.resolve({ options: [] })
}
const queryString = {
query: query,
companyStateId: companyStateId,
}
console.log('queryString', queryString)
return getSuburbs(queryString)
.then(data => {
console.log('Suburbs returned!', data)
console.groupEnd()
return { options: data }
})
}
//I HAVE MOVED IT TO HERE....
onSuburbChange = (value) => {
this.setState({ selectedSuburb: value }, () => {
input.onChange(value)
updatePostcodeValue(value ? value.postcode : null, sectionPrefix)
})
}
render() {
const { addressData, updatePostcodeValue } = this.props
const { value } = this.state
const sectionPrefix = this.context._reduxForm.sectionPrefix
return (
<Panel header={<h3>Client - Address Details</h3>}>
<Row>
<Field component={TextField}
name="address1"
id="address1"
type="text"
label="Address Line 1"
placeholder="Enter street 1st line..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
<Field component={TextField}
name="address2"
id="address2"
type="text"
label="Address Line 2"
placeholder="Enter street 2nd line..."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field
component={props => {
const { input, id, placeholder, type } = props
const { fieldCols, labelCols, controlCols, label, inputClass } = props
// just the props we want the inner Typeahead textbox to have
const { name, onChange } = input
const onStateChange = (state) => {
console.log('onStateChange', state)
onChange(state)
}
return (
<FormField
id={id}
label={label}
fieldCols={fieldCols}
labelCols={labelCols}
controlCols={controlCols}
inputClass={inputClass}
>
<Select
name={name}
onChange={onStateChange}
placeholder="Select state"
valueKey="id"
options={addressData.states}
labelKey="stateLabel"
optionRenderer={option => `${option.stateShortName} (${option.stateName})`}
value={input.value}
selectValue={Array.isArray(input.value) ? input.value : undefined}
/>
</FormField>
)
}}
name="state"
id="state"
label="State."
fieldCols={6}
labelCols={3}
controlCols={6}
/>
</Row>
<Row>
<Field
component={props => {
const { input, id, placeholder, type } = props
const { fieldCols, labelCols, controlCols, label, inputClass } = props
const { name, value, onChange, onBlur, onFocus } = input
const inputProps = {
name,
value,
onChange,
onBlur,
onFocus,
}
{/*onSuburbChange = (value) => {
this.setState({ selectedSuburb: value }, () => {
input.onChange(value)
updatePostcodeValue(value ? value.postcode : null, sectionPrefix)
})
}*/}
return (
<FormField
id={id}
label={label}
fieldCols={fieldCols}
labelCols={labelCols}
controlCols={controlCols}
inputClass={inputClass}
>
<Select.Async
{...inputProps}
onChange={this.onSuburbChange}
valueKey="id"
labelKey="suburbName"
loadOptions={this.handleSuburbSearch}
backspaceRemoves={true}
/>
</FormField>
)
}}
name="suburb"
id="AddressLocation"
label="Suburb."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
<Row>
<Field component={StaticText}
name="postcode"
id="postcode"
label="Postcode."
fieldCols={6}
labelCols={3}
controlCols={9}
/>
</Row>
</Panel>
)
}
}
const AddressContainer = connect(state => ({
addressData: state.addressData,
}), dispatch => ({
updatePostcodeValue: (postcode, sectionPrefix) => dispatch(change(CLIENT_FORM_NAME, `${sectionPrefix ? (sectionPrefix + '.') : ''}postcode`, postcode))
}))(Address)
export default AddressContainer
How do I structure the onSuburbChange so that it can sit outside the render function, update the onChange value and also update the Postcode etc?
well, if you look at the method, you'll see that... well, input is undefined in that scope.
onSuburbChange = (value) => { // <-- scope starts here
this.setState({ selectedSuburb: value }, () => {
input.onChange(value) // <-- input used here
updatePostcodeValue(value ? value.postcode : null, sectionPrefix)
})
}
assuming Select.Async is a "magic" blackbox Component that you don't have access to/are able to change, and the only parameter you get back from it in the callback is the new value, your best bet is a ref on the input.
<Field ref={(input) => this.input = input } ... />
and then change it to this.input instead of just input
I think you could also partially apply it (it's late any I'm not thinking straight) - it would look like
onSuburbChange = (input, value) => {
this.setState({ selectedSuburb: value }, () => {
input.onChange(value)
updatePostcodeValue(value ? value.postcode : null, sectionPrefix)
})
}
--
const mOnChange = onSuburbChange.bind(null, input) while input is in scope.
updatePostcodeValue can be referenced from props in the callback - and you've already taken care of ensuring it has the correct scope by using ES6 arrow function notation. Just destructure it out of props just like you did in render at the top of the callback.
also, unrelated, but you REALLY oughta break out those component props into another file or function...

Categories

Resources