I want to add React component to DOM. Next, I need to remove (hide) that. Then, I want to add (show) again that with all data entried.
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = { value: '' };
this.handleChange = this.handleChange.bind(this);
}
handleChange(e) {
this.setState({ value: e.target.value })
}
render() {
return <input type="text" onChange={this.handleChange} name="name" />
}
in parent Component:
<div>
{this.state.show && < MyComponent />}
<button onClick={() => { this.setState({ show: !this.state.show }) }} >change</button>
</div>
There will be few steps here...
Declare a state as const [show,setShow] = useState()
Now render the DOM element conditionally, like
show ? element1 : element2
The only solution is to use style.
We can send the status as a parameter to the component else component will be load again and data'll be clear
Related
React Semantic - TextArea
I have initial value
which is showing in the textArea but its not editable anymore.
Any solution?
codepen example:
[1]: https://codepen.io/as3script/pen/VRepqv?editors=1010
You can use state for this purpose
const {
TextArea,
} = semanticUIReact
class App extends React.Component {
constructor(props){
super(props);
this.state={
value: "initial text which I would like to edit" // set initial state
}
}
onChange(e){
this.setState({ value: e.target.value })
}
render() {
const { value } = this.state;
return (
<div>
<TextArea
rows={4}
style={{'width': '550'}}
onChange={(e) => this.onChange(e)}
value={value} //render changed state
/>
</div>
)
}
}
// ----------------------------------------
// Render to DOM
// ----------------------------------------
const mountNode = document.createElement('div')
document.body.appendChild(mountNode)
ReactDOM.render(<App />, mountNode)
I want to make a component with an API like any standard input element, meaning I want to use it like this: <CustomInput value={this.state.custom_input_state} onChange={this.handleChange} />
Here is what I have so far, but I have no idea how to
Make the custom components value changeable from the parent component
after it has been constructed
Make the parent's onChange handler function recieve a change event when the
custom component's value changes
Here is my test setup:
class Form extends React.Component {
constructor(props) {
super(props);
this.state = {
foo: 0
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.increment = this.increment.bind(this);
}
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
handleSubmit(event) {
alert(this.state.foo);
event.preventDefault();
}
increment() {
this.setState({foo: this.state.foo + 1});
}
render() {
return(
<form onSubmit={this.handleSubmit}>
<div onClick={this.increment}>Increment from parent</div>
<CustomInput name="foo" value={this.state.foo} onChange={this.handleChange}/>
<input type="submit" value="Submit" />
</form>
)
}
}
class CustomInput extends React.Component {
constructor(props) {
super(props);
this.state = {
value: this.props.value,
};
this.increment = this.increment.bind(this);
}
increment() {
this.setState({value: this.state.value + 1});
}
render() {
return(
<React.Fragment>
<div onClick={this.increment}>Increment self</div>
<input name={this.props.name} value={this.state.value}/>
</React.Fragment>
);
}
}
You have to pass all the CustomInput props to the input element. In CustomInput component actually it not recieving the onChange event.
Pass the prop onChange event to input element
Form Component
class Form extends Component {
constructor() {
super();
this.state = {
foo: 'React'
};
}
handleChange = (event) => {
this.setState({
[event.target.name]:event.target.value
})
}
render() {
return (
<div>
<form>
<Custominput name="foo" onChange={this.handleChange} value={this.state.foo} />
</form>
{this.state.foo}
</div>
);
}
}
CustomInput Component
export default class CustomInput extends React.Component{
render(){
return(
<input {...this.props} />
)
}
}
demo link
In Reactjs if I have two child components of an App component, can I take input from one component and output it in the other child component?
class App extends Component{
render(
<Input/>
<Output/>
)
}
Input = () => { //input }
Output = () => { //output }
It's simple. Use the same state value for both components in the parent component:
class App extends Component{
constructor(props){
super(props);
this.state = {
value: ''
}
onValueChange = thisonValueChange.bind(this);
}
onValueChange(e) {
e.preventDefault();
setState({
value: e.target.value
});
}
render(){
return(
<Input value={this.state.value} onChange={this.onValueChange} />
<Output value={this.state.value}/>
);
}
}
Input = (props) => {
<input value={props.value} onChange={props.onValueChange}>
}
Output = (props) => <div>{props.value}</div>);
You can handle the data in the App component via state by passing a handler down to the Input component
and then pass the state value down to the Output component like
const Input = props => <input onChange={props.handleChange} />
const Output = props => <span>{props.data}</span>
class App extends Component {
state = {data:""}
handleChange = e => {
this.setState({ data: e.target.value })
}
render() {
return (
<div>
<Input handleChange={this.handleChange} />
<Output data={this.state.data} />
</div>
)
}
}
`export class Parent extends React.Component{
constructor(props){
super(props);
this.state={
name:'',
sendData:false
}
}
render(){
return (<div><input type="text" onChange={(event)=>
{this.setState({
name:event.target.value,
})
})
/>
//sendData can be made true on a button click
{this.state.sendData ?(<div><Child name={this.state.name}
/>
</div>):null}
</div>)}
}`
Display the data of Parent in the child component.
`export class Child extends React.Component{
render(){
return (<div>Name is :{this.props.name}</div>)
}
}`
I have a constructor in my main component:
class App extends Component {
constructor(props){
super(props);
this.state = {
items: []
}
};
render() {
return (
<div className="App">
<ItemList items={this.state.items}/>
<AddItemForm items={this.state.items}/>
</div>
);
}
}
In component AddItemForm I'm adding to array items objects with properties "item_name" that is string and "comment" with data type object. View of component:
class AddItemForm extends React.Component {
constructor(props) {
super(props);
this.state = {
item:{}
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({item:
{
item_name: event.target.value,
comment:{}
}
});
}
handleSubmit(event) {
event.preventDefault();
this.props.items.push(this.state.item);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" item_name={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default AddItemForm;
How can I iterate this array to get all item_name values of every object and display them as list in my ItemList component?
This should help.
class App extends Component {
constructor(props){
super(props);
this.state = {
items: []
}
};
addItemToItemsList = (item) => {
const {items=[]} = this.state;
items.push(item);
this.setState({
items : items
});
}
render() {
return (
<div className="App">
<ItemList items={this.state.items}/>
<AddItemForm
items={this.state.items}
addItemToItemsList={this.addItemToItemsList}
/>
</div>
);
}
}
class ItemList extends React.Component {
render () {
const {items} = this.props;
return (
<div>
{items.map((item, index) => {
return (
<div key={index}>item.item_name</div>
)
})}
</div>
);
}
}
class AddItemForm extends React.Component {
constructor(props) {
super(props);
this.state = {
item: {
item_name : '',
comment:{}
}
};
}
handleChange = (event) => {
const new_item = Object.assign({}, this.state.item, {item_name: event.target.value});
this.setState({
item: new_item
});
}
handleSubmit = (event) => {
event.preventDefault();
this.props.addItemToItemsList(this.state.item);
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
<input type="text" item_name={this.state.item.item_name} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
export default AddItemForm;
I think, you have an error inside AddItemForm, you should pass onSubmit function from App to AddItemForm and change items through this function:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
items: []
}
this.handleSubmit = this.handleSubmit.bind(this);
};
handleSubmit(value){
this.setState({
items: this.state.items.concat(value)
})
}
render() {
return (
<div className="App">
<ItemList items={this.state.items} />
<AddItemForm
onSubmit={this.handleSubmit}
items={this.state.items} />
</div>
);
}
}
About main question, one of the way to solve this problem
const ItemList = ({items}) => (
<div>
{items.map( (item, index)=> (
<div key={index}>{item.item_name}</div>
))}
</div>
);
full working example here: https://codesandbox.io/s/7k624nz94q
You can't add to the array directly. You need to pass a callback that will add to the array in your parent component's state. This is a very common pattern when using react.
Here is a skeleton of what you need to do:
In your parent component, you don't need to pass the whole list to your AddItemForm component, just a addItem callback to your child component:
class App extends Component {
constructor(props){
super(props);
this.state = {
items: []
}
this.addItemToList = this.addItemToList.bind(this);
};
render() {
return (
<div className="App">
<ItemList items={this.state.items}/>
<AddItemForm addItemToList={this.addItemToList}/>
</div>
);
}
addItemToList(newValue) {
// Here you add the item to your state
// Always treat your state as immutable, so create a copy then add the item, then set your new State
const newArray = this.state.items.slice(); // clone
newArray .push(newValue); // Add value
this.setState({items: newArray}); // Set the new state
}
}
More info on how to add items to an array in the state here: React.js - What is the best way to add a value to an array in state
Then you use that callback in your child component:
handleSubmit(event) {
event.preventDefault();
// this.props.items.push(this.state.item);
// Here don't mutate the props, instead call the callback to add the item to your parent's component's state
this.props.addItemToList(this.state.item);
}
To display a list of items, you need to use the map function: https://reactjs.org/docs/lists-and-keys.html#rendering-multiple-components
I am new to react, I thought setting state will re-render react component. Did I miss something here, my text is not displayed until I call this.forceUpdate().
export default class Hello extends React.Component {
constructor(props){
super(props);
this.state = { value: ''};
this.handleChange = this.handleChange.bind(this);
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
<p> You entered {this.state.value} </p>
</div>
);
}
handleChange(event){
this.state = { value: event.target.value };
this.forceUpdate();
}
}
You should call .setState method instead of assign new value to this.state
handleChange(event){
this.setState({ value: event.target.value })
}