React doesn´t rerender ComponentDidUpdate after react-select Input changed state - javascript

I am really lost on this one:
import React, { Component } from "react";
import Select from "react-select";
class selectDemo extends Component {
state = {
selectedOption: "",
data: [{ Model: "Option1" }, { Model: "Option2" }]
};
handleChange = selectedOption => {
this.setState({ selectedOption }, () =>
console.log(this.state.selectedOption.Model)
);
};
renderButton = () => {
return (
<button type="button" class="btn btn-primary">
{this.state.selectedOption.Model}
</button>
);
};
componentDidUpdate(prevProps, prevState) {
if (this.state.selectedOption !== prevState.selectedOption) {
this.renderButton();
}
}
render() {
const { selectedOption } = this.state;
const value = selectedOption && selectedOption.Model;
return (
<div>
<div name="selectedOption" className="section">
<Select
className="form-control"
placeholder="Select Option"
name="selectedOption"
value={value}
onChange={this.handleChange}
labelKey="Model"
valueKey="Model"
optionClassName="dropdown-item"
options={this.state.data}
/>
</div>
<div className="form-group">{this.renderButton}</div>
</div>
);
}
}
export default selectDemo;
All I want to achieve is that after I made a Selection from a dropDown List created with the react-select package a button gets rendered on the page. Everything is working fine except for the fact that the button does not get rendered when a selection has been made. Anyone has an idea where I am wrong?

You have to call renderButton explicitly this.renderButton()
here is the right way :
class SelectDemo extends React.Component {
state = {
selectedOption: "",
data: [{ Model: "Option1" }, { Model: "Option2" }]
};
handleChange = selectedOption => {
this.setState({ selectedOption }, () =>
console.log(this.state.selectedOption.Model)
);
};
renderButton = () => {
return (
<button type="button" className="btn btn-primary">
{this.state.selectedOption.Model}
</button>
);
};
render() {
const { selectedOption } = this.state;
const value = selectedOption && selectedOption.Model;
return (
<div>
<div name="selectedOption" className="section">
<Select
className="form-control"
placeholder="Select Option"
name="selectedOption"
value={value}
onChange={this.handleChange}
labelKey="Model"
valueKey="Model"
optionClassName="dropdown-item"
options={this.state.data}
/>
</div>
{this.state.selectedOption && <div className="form-group">{this.renderButton}</div>}
<div className="form-group">{this.renderButton()}</div>
</div>
);
}
}

You are missing the function call to your this.renderButton in your main render function. It should look like:
<div className="form-group">{this.renderButton()}</div>
Also, in your componentDidUpdate, you are calling this.renderButton() but that will not cause it to render the returned markup. The state update from your handleChange will trigger the re-render of your component without you needing to check in componentDidUpdate.

Related

clear search box after onclick

I have a search box in my header. i can clear my state after searching but the input doesn't get cleared.
I'm purely using the Searchbox to generate a dropdown that contains links to their respective field. So the input field is purely used to mimic a searc
I tried targeting it with refs but when i finally reach the value i can't use the search anymore.
There is a ref for SearchBarHeader, SearchBox and SearchField. But i'm not sure if that is the correct way to do it.
clearSearchBar = () => {
this.searchBarHeader.current.searchBox.current.searchField.current.value = '';
};
and the code for the searchbox.
class Search extends Component {
state = {
organisationNames: [],
errorMessage: null,
};
searchField = React.createRef();
async componentDidMount() {
const organisations = await getSearch();
this.setState({
organisationNames: organisations,
});
}
searchHandler = (e) => {
const searchValue = e.target.value.toLowerCase();
if (!searchValue) {
this.props.clearSearchResult();
} else {
const result = this.state.organisationNames.filter((organisationName) => {
return organisationName.toLowerCase().includes(searchValue);
});
this.props.setSearchResult(result, () => {
if (this.props.searchResult.length === 0) {
this.setState({
errorMessage: "No Results...",
});
} else {
this.setState({
errorMessage: null,
});
}
});
}
};
clearSearchInput = () => {
this.props.clearSearchResult();
};
render() {
return (
<div className="search">
<div className="form-group">
<input
ref={this.searchField}
type="search"
placeholder="Search for company"
onChange={this.searchHandler}
/>
</div>
<div className="search-result-wrapper">
<ul className="search-results">
{this.props.searchResult === undefined ? (
<Skeleton />
) : (
this.props.searchResult.map((res, id) => {
return (
<Link
key={id}
to={"/r/" + res}
onClick={this.clearSearchInput}
>
<li className="search-item">{res || <Skeleton />} </li>
</Link>
);
})
)}
{this.state.errorMessage === null ? (
""
) : (
<li>{this.state.errorMessage}</li>
)}
</ul>
</div>
</div>
);
}
}
export default Search;
It seems to me that you're missing the "value" attribute on your input that makes it reactive to changes in your state. Grabbing one example from react docs, here's the ideal setup:
this.state = {value: ''};
(...)
handleChange(event) {
this.setState({value: event.target.value});
}
(...)
<input type="text" value={this.state.value} onChange={this.handleChange} />
By following the method above, you won't need to use refs to manually clear the input value. Once the form is submitted, you can simply clear your state...
this.setState({value: ''});
... and your input should be cleared.
Here's the link for the docs: https://reactjs.org/docs/forms.html
You are clearing the ref, not the state. There is also not a value attached to your input, so even if the state was cleared, it will not reflect.
You will of course be able to make the form data more dynamic, without having to set and keep companyName constant.
Here is a simple working example is here: https://codesandbox.io/s/flamboyant-voice-oj85u?file=/src/App.js
export default function App() {
const [formData, setFormData] = useState({ companyName: "" });
const handleChange = (e) => {
setFormData({ companyName: e.target.value });
};
const handleClear = () => {
setFormData({ companyName: "" });
};
return (
<div className="search">
<div className="form-group">
<input
type="search"
name="companyName"
value={formData.companyName}
placeholder="Search for company"
onChange={handleChange}
/>
<button onClick={handleClear}>Clear</button>
</div>
<pre>{JSON.stringify(formData, null, 2)}</pre>
</div>
);
}

how to Uncheck Checkbox.Group in Antd React.js

I have the following Code using https://ant.design/components/checkbox/, and Trying to uncheck when a checkbox has been checked.
I don't want to check all if button is click, just Uncheck all or the one checkbox selected.
constructor(props) {
super(props);
this.state = {
checked: true,
}
this.onChange = this.onChange.bind(this);
}
onChange(value) {
this.props.onChangeSession(value)
}
onChangeBox = e => {
this.setState({
checked: e.target.checked,
});
};
unChecked = () => {
this.props.onChangeSession([])
this.setState({
checked: false
});
};
render () {
const {
data,
} = this.props
return (
<div>
<Button type="primary" size="small" onClick={this.unChecked}>
Uncheck
</Button>
<Checkbox.Group
style={{ width: '100%' }}
onChange={this.onChange}>
<div>
<div className="filter-subhead">Track</div>
{data.map(i =>
<div className="filter-item">
<Checkbox
checked={this.state.checked}
onChange={this.onChangeBox}
value={i}>{i}</Checkbox>
</div>
)}
</div>
</Checkbox.Group>
</div>
)
}
Any help will be appreciate!
Working Link
The toggle on the checkbox wasn't working due to Checkbox.Group, you can simply use Checkbox
Regarding Checkbox State:
You can't have a single state for all the checkboxes, so you will need to have an array of bool which will serve as the state for each checkbox item.
In the example, I have initialized checkbox state on componentDidMount and it creates an array ([false,false,false,...]) and the exact same thing is used for resetting on Uncheck. (Possibility of refactoring in my code)
User assigned state will decide whether to check the checkbox or not.
import React from "react";
import ReactDOM from "react-dom";
import { Button, Checkbox } from "antd";
import "antd/dist/antd.css";
import "./index.css";
let data = [3423, 3231, 334234, 55345, 65446, 45237];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
checkboxArray: []
};
// this.onChange = this.onChange.bind(this);
}
componentDidMount() {
let createEmptyArray = new Array(data.length).fill(false);
this.setState({ checkboxArray: createEmptyArray });
}
onChange(e) {
console.log(e.target);
}
onChangeBox = (e, i) => {
let checkBoxCurrentState = this.state.checkboxArray;
checkBoxCurrentState[i] = !checkBoxCurrentState[i];
this.setState({
checkboxArray: checkBoxCurrentState
});
};
unChecked = e => {
let resetArray = new Array(data.length).fill(false);
this.setState({
checkboxArray: resetArray
});
};
render() {
const { data } = this.props;
return (
<div>
<Button type="primary" size="small" onClick={this.unChecked}>
Uncheck
</Button>
<div>
<div className="filter-subhead">Track</div>
{data.map((i, index) => (
<div className="filter-item">
<Checkbox
checked={this.state.checkboxArray[index] ? true : false}
onChange={e => this.onChangeBox(e, index)}
value={index}
>
{JSON.stringify(this.state.checkboxArray[index])}
</Checkbox>
</div>
))}
</div>
{JSON.stringify(this.state.checkboxArray)}
</div>
);
}
}
ReactDOM.render(<App data={data} />, document.getElementById("root"));
Simple copy and paste the above code and add props where required.
And if you want to user Checkbox.Group, will need to update the onChange method of CheckBox.Group
let data = ['Apple', 'Pancakes', 'Butter', 'Tea', 'Coffee'];
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
checkboxArray: []
};
// this.onChange = this.onChange.bind(this);
}
componentDidMount() {
let createEmptyArray = new Array(this.props.data.length).fill(false);
this.setState({ checkboxArray: createEmptyArray });
}
onChangeBox = (e, i) => {
let checkBoxCurrentState = this.state.checkboxArray;
checkBoxCurrentState[i] = !checkBoxCurrentState[i];
this.setState({
checkboxArray: checkBoxCurrentState
});
};
unChecked = () => {
let resetArray = new Array(data.length).fill(false);
this.setState({
checkboxArray: resetArray
});
};
render() {
const { data } = this.props;
return (
<div>
<button onClick={this.unChecked}>Clear All</button>
{this.props.data.map((single, index) => (
<div>
<input
type="checkbox"
id={index}
name="scales"
checked={this.state.checkboxArray[index]}
onChange={e => this.onChangeBox(e, index)}
/>
<label for={index}>{single}</label>
</div>
))}
</div>
);
}
}
ReactDOM.render(<App data={data} />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
If you're going to use a map to dynamically generate the checkboxes, using state to keep track of checked value will be tricky. You should not do this.
What you should do is not include the checked prop at all in the component.
<Checkbox
onChange={this.onChangeBox}
value={i}>{i}
</Checkbox>
The checkbox should still check even if you do not include the checked prop. It's a little strange, I know.
Instead just pass the value into the onChangeBox function and handle all your logic there and set a state value on change.
I just tested it out and it works.

Force input's onChange event bubble to parent form with the value stored in the state

EDIT
Sorry for showing wrong use-case. All inputs inside the Form are being passed though this.props.children, and they can be situated at any deep point of the components tree, so the approach of passing the handleChange directly to inputs will not work at all.
Here is code snippet with the reproduction of the problem.
class CustomSelect extends React.Component {
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
]
state = {
selected: null,
}
handleSelect = (item) => {
this.setState({ selected: item })
}
render() {
var { selected } = this.state
return (
<div className="custom-select">
<input
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected
? selected.id
: ""
}
onChange={() => {}}
/>
<div>Selected: {selected ? selected.text : "nothing"}</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.handleSelect(item)}
>
{item.text}
</button>
)
})}
</div>
)
}
}
class Form extends React.Component {
handleChange = (event) => {
console.log("Form onChange")
}
render() {
return (
<form onChange={this.handleChange}>
{this.props.children}
</form>
)
}
}
ReactDOM.render(
<Form>
<label>This input will trigger form's onChange event</label>
<input />
<CustomSelect name="kappa" />
</Form>,
document.getElementById("__root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="__root"></div>
As you can see, when you type something in default input (controlled or uncontrolled, whatever), form catches bubbled onChange event. But when you are setting the value of the input programmatically (with the state, in this case), the onChange event is not being triggered, so I cannot catch this changes inside the form's onChange.
Is there any options to beat this problem? I tried to input.dispatchEvent(new Event("change", { bubbles: true })) immediately after setState({ selected: input }) and inside it's callback, but there is no result.
I really think the best to do what you try to do is first make sure to control each individual input. Keep those values in state and just working with the onSubmit event from the form. React even recommended this approach here https://reactjs.org/docs/uncontrolled-components.html
In most cases, we recommend using controlled components to implement
forms. In a controlled component, form data is handled by a React
component. The alternative is uncontrolled components, where form data
is handled by the DOM itself.
You can read about controlled here https://reactjs.org/docs/forms.html#controlled-components
If you want to see how I will have made with just control this will have been looks like that https://codesandbox.io/s/2w9qnk8lxp You can see if you click enter the form submit event with the value keep in state.
class CustomSelect extends React.Component {
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
];
render() {
return (
<div className="custom-select">
<div>
Selected: {this.props.selected ? this.props.selected.text : "nothing"}
</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.props.onChange(item)}
>
{item.text}
</button>
);
})}
</div>
);
}
}
class Form extends React.Component {
state = {
firstInput: "",
selected: null
};
handleSubmit = event => {
event.preventDefault();
console.log("Form submit", this.state);
};
handleInputChange = name => event => {
this.setState({ [name]: event.target.value });
};
handleSelectedChanged = selected => {
this.setState({ selected });
};
render() {
console.log(this.state);
return (
<form onSubmit={this.handleSubmit}>
<label>This input will trigger form's onChange event</label>
<input
value={this.state.firstInput}
onChange={this.handleInputChange("firstInput")}
/>
<CustomSelect
name="kappa"
selected={this.state.selected}
onChange={this.handleSelectedChanged}
/>
</form>
);
}
}
But if you really want your way, you should pass down the handleChange function as a callback to the children and make use of this props as a function when you click on an element. Example here https://codesandbox.io/s/0o8545mn1p.
class CustomSelect extends React.Component {
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
];
state = {
selected: null
};
handleSelect = item => {
this.setState({ selected: item });
this.props.onChange({ selected: item });
};
render() {
var { selected } = this.state;
return (
<div className="custom-select">
<input
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected ? selected.id : ""}
onChange={() => {}}
/>
<div>Selected: {selected ? selected.text : "nothing"}</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.handleSelect(item)}
>
{item.text}
</button>
);
})}
</div>
);
}
}
class Form extends React.Component {
handleChange = event => {
console.log("Form onChange");
};
render() {
return (
<form onChange={this.handleChange}>
<label>This input will trigger form's onChange event</label>
<input />
<CustomSelect name="kappa" onChange={this.handleChange} />
</form>
);
}
}
If you pass down the function from the form you can trigger it manually. You just need to create the new Event() to suite you needs of info. Since its a prop it will sync if any method changes happen in the parent element.
Since you use props to generate elements within the form you must map them like so. This was the event only gets added to the custom elements.
class CustomSelect extends React.Component {
propTypes: {
onChange: React.PropTypes.func
}
items = [
{ id: 1, text: "Kappa 1" },
{ id: 2, text: "Kappa 2" },
{ id: 3, text: "Kappa 3" }
]
state = {
selected: null,
}
handleSelect = (item) => {
this.setState({ selected: item });
this.props.onChange.self(new Event('onchange'))
};
render() {
var { selected } = this.state
return (
<div className="custom-select">
<input
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected
? selected.id
: ""
}
onChange={() => {}}
/>
<div>Selected: {selected ? selected.text : "nothing"}</div>
{this.items.map(item => {
return (
<button
key={item.id}
type="button"
onClick={() => this.handleSelect(item)}
>
{item.text}
</button>
)
})}
</div>
)
}
}
class Form extends React.Component {
handleChange = (event) => {
console.log("Form onChange")
}
render() {
let self = this.handleChange;
let children = React.Children.map(this.props.children, (child, i) => {
if(typeof child.type === "function"){
return React.cloneElement(child, {
onChange: {self}
});
}
return child;
});
return (
<form onChange={this.handleChange}>
{children}
</form>
)
}
}
ReactDOM.render(
<Form>
<label>This input will trigger form's onChange event</label>
<input />
<CustomSelect name="kappa" />
</Form>,
document.getElementById("__root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="__root"></div>
Update your CustomSelect component with the following:
class CustomSelect extends React.Component {
...
// you'll use this reference to access the html input.
ref = React.createRef();
handleSelect = item => {
this.setState({ selected: item });
// React overrides input value setter, but you can call the
// function directly on the input as context
const inputValSetter = Object.getOwnPropertyDescriptor(
window.HTMLInputElement.prototype,
"value"
).set;
inputValSetter.call(this.ref.current, "dummy");
// fire event
const ev = new Event("input", { bubbles: true });
this.ref.current.dispatchEvent(ev);
};
...
render() {
...
return (
<div className="custom-select">
<input
// you'll use the reference in `handleSelect`
ref={this.ref}
name={this.props.name}
required
style={{ display: "none" }} // or type="hidden", whatever
value={selected ? selected.id : ""}
onChange={() => {}}
/>
...
</div>
);
}
...
}
And your Form component with the following:
class Form extends React.Component {
handleChange = event => {
console.log("Form onChange");
// remove synthetic event from pool
event.persist();
};
...
}

How to Update This Reactjs Select

I have this wrapper class that is used because I am using Formik and the FieldArray
import React, { Component } from "react";
import { ReactDOM } from "react-dom";
import Select from "react-select";
import { observer } from "mobx-react";
import { axiosInstance } from "../stores/AxiosInstance";
#observer
export default class CountryStateSelectComponent extends React.Component {
constructor(props) {
super(props);
this.state = { stateOptions: [] };
}
handleCountryChange = value => {
const that = this;
axiosInstance
.get(`/States?countryId=${value.value}`)
.then(function(response) {
that.props.onChange(that.props.countryName, value);
that.props.onChange(that.props.stateName, null);
const states = response.data.map(state => {
return { label: state.name, value: state.id };
});
// if I move out state select code then won't need to update state here but don't know how to call something like updateState(record)
that.setState({
stateOptions: states
});
});
};
handleStateChange = value => {
console.log(this.props.stateName, value)
this.props.onChange(this.props.stateName, value);
};
handleCountryBlur = () => {
this.props.onBlur(this.props.countryName, true);
};
handleStateBlur = () => {
this.props.onChange(this.props.stateName, true);
};
render() {
const props = this.props;
return (
<React.Fragment>
<div className="field">
<label className="label">Country</label>
<div className="control">
<Select
options={props.options}
isMulti={props.isMulti}
onChange={this.handleCountryChange}
onBlur={this.handleCountryBlur}
closeMenuOnSelect={props.closeMenuOnSelect}
/>
{this.props.CountryError}
</div>
</div>
<div className="field">
<label className="label">State/Province</label>
<div className="control">
<Select
options={this.state.stateOptions}
onChange={this.handleStateChange}
onBlur={this.handleStateBlur}
/>
{this.props.StateError}
</div>
</div>
</React.Fragment>
);
}
}
However what I found is that when the State gets selected the value does not get stored in Formik(it gets stored as undefined and sometimes true).
So now I am thinking maybe moving out the State Zip out and making it's own wrapper or something but I don't know how to get the "states" that came back and populate the correct state box as they can generate many.
#inject("AccountSetupStore")
#observer
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = { records: [this.generateRecord(1, true, true)] };
}
componentDidMount() {
const accountSetupStore = this.props.AccountSetupStore;
accountSetupStore.getCountries();
}
updateState(record) {
// would like to call this method that can somehow update the record
// propblem is I don't seem to have access to props when this function is being called from the CountryStateSelectComponent
}
render() {
const props = this.props;
const accountSetupStore = props.AccountSetupStore;
const countries = [];
for (const country of accountSetupStore.countries) {
countries.push({ value: country.id, label: country.name });
}
return (
<section className="accordions">
<Formik
initialValues={{
records: this.state.records
}}
onSubmit={(
values,
{ setSubmitting, setErrors}
) => {
console.log(values,"values");
}}
validationSchema={Yup.object().shape({
branches: Yup.array()
.of(
Yup.object().shape({
})
)
})}
render={({
values,
setFieldValue,
setFieldTouched,
}) => (
<FieldArray
name="records"
render={arrayHelpers => (
<Form>
{values.records.map((record, index) => {
return (<article}>
<CountryStateSelectComponent options={countries}
onChange={setFieldValue}
countryName={`records[${index}].selectedCountry`}
stateName={`records[0].selectedState`}
onBlur={setFieldTouched}
isMulti={false}
index = {index}
closeMenuOnSelect={true}
CountryError = {<ErrorMessage name={`records[${index}].selectedCountry`}/>}
StateError= {<ErrorMessage name={`records[${index}].selectedState`}/>}
/>
</article>)
})}
</Form>
)}
/>
)}
/>
</section>
);
}
}
React Select onChange sends the value to the method supplied
const onStateChange = (selectedOption, {action}) => {
//do something with the selectedOption according to the action
}
<Select onChange={onStateChange} />
See the documentation for the onChange in the Props documentation.

ReactJS - How to change a component's state based on another component

Im trying to update a component's state when a different component's state changes.
Here is the main component that contains the form:
class IpsumForm extends React.Component {
state = {
character: 'All',
paragraphs: 1,
ipsumDisplayed: false
};
handleInputChange = (e) => {
const target = e.target;
this.setState({ paragraphs: target.value });
};
handleSelectChange = (e) => {
const target = e.target;
this.setState({ character: target.value });
};
handleReset = (e) => {
this.setState({
character: 'All',
paragraphs: 1,
ipsumDisplayed: false
});
};
handleSubmit = (e) => {
e.preventDefault();
this.setState({
ipsumDisplayed: true
});
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<p>Select Your Character:</p>
<select
value={this.state.character}
onChange={this.handleSelectChange}
name="characterPick"
>
<option value="All">All</option>
<option value="Michael">Michael</option>
<option value="Dwight">Dwight</option>
<option value="Jim">Jim</option>
<option value="Andy">Andy</option>
<option value="Creed">Creed</option>
</select>
<div className="length">
<p>How Many Paragraphs?</p>
<input
onChange={this.handleInputChange}
name="paragraphLength"
type="text"
/>
</div>
<hr />
<input
id="submit"
type="submit"
value="Bibity Boppity Give Me The Zoppity"
/>
<button onClick={this.handleReset}>Reset</button>
</form>
<br />
<IpsumText
person={this.state.character}
length={this.state.paragraphs}
displayed={this.state.ipsumDisplayed}
/>
</div>
);
}
}
export default IpsumForm;
And here is the component that I would like to return the ipsum within a textbox:
class IpsumText extends React.Component {
state = {
value: ''
};
handleValueChange = (e) => {
console.log(data.quote1);
this.setState({
value: data.quote1
});
};
render() {
let character = this.props.person;
let paragraphs = this.props.length;
let displayed = this.props.displayed;
return (
<div className="returned-ipsum">
<textarea value={this.state.value} onChange={this.handleValueChange} />
</div>
);
}
}
export default IpsumText;
The code I have now doesn't work because a state change from the IpsumForm doesn't cause the textarea onChange handler to run in the IpsumText
I'm wondering if there is a way to do this other than using a lifecycle method because it seems like i'm just overthinking it
Here's a very simple way of looking at it:
class App extends React.Component {
state = {
firstState: 1,
}
handleStateUpdate = () => {
this.setState(prev => ({
firstState: prev.firstState + 1
}))
}
render() {
console.log(this.state.firstState)
return (
<Foo handleStateUpdate={this.handleStateUpdate} />
)
}
}
class Foo extends React.Component {
state = {
otherState: 1,
}
handleLocalStateUpdate = () => {
this.props.handleStateUpdate()
this.setState(prev => ({
otherState: prev.otherState + 1
}))
}
render() {
return <button onClick={() => this.handleLocalStateUpdate()}>Click here!</button>
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app'></div>
What this is doing is passing down a function from the parent that updates the parent state, down to the child component. Once you define a function that updates the state of the child component, you can call that passed down function to also update the parent state.
Hopefully, the principle of doing this helps with the issue you're facing.
Here's a link to the code in case you wanna mess with it:
CodePen

Categories

Resources