I am trying to do to do list. Onclick I want to add tag p with value from input, but it gives me error. I want to do like this:
I have array in state with name items, onclick I add value from input to my item array, then in return I make map function which return tag p with text value. What I am doing wrong?
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', items: []};
this.handleChange = this.handleChange.bind(this);
this.showValue = this.showValue.bind(this);
}
handleChange(event) {
this.setState({text: event.target.value});
}
showValue() {
var newItem = {
text: this.state.text
};
this.setState({
items: this.state.items.concat(newItem)
})
}
render() {
return (
<div>
<input type="text" value={this.state.text} onChange={this.handleChange} />
<button onClick={this.showValue}>Add</button>
{this.state.items.map(function() {
<p>{this.state.text}</p>
})}
</div>
);
}
}
ReactDOM.render(
<NameForm />,
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>
In your example, you're using your state inside the mapping function, which is not what you want to do. Instead, you want to map every item inside the state, that's why you begin that part of the code with this.state.items.map.
In your map function, you get your individual items, so you can actually use your item that you added before to your state and get the text by doing {item.text}.
You need to make sure you're actually returning the <p> too inside your map function, like:
{
this.state.items.map(function(item) {
return <p>{item.text}</p>;
})
}
Working code here:
Related
class Demo extends React.Component{
constructor (){
super();
this.state = {
list : ['car','map', 'house']
}
}
inputValue(e){
var x = e.target.value;
console.log(x)
}
addValue(){
this.state.list.push();
this.setState({list: this.state.list});
}
render(){
return(
<div>
<input onChange={this.inputValue} type="text"/>
<ul>
{this.state.list.map(item => (
<li>{item}</li>
))}
</ul>
<button onClick={this.addValue.bind(this)}>Add Element</button>
</div>
)
}
}
ReactDOM.render(
<Demo/>,
document.getElementById('test')
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.1/umd/react-dom.production.min.js"></script>
<div id="test"></div>
Using my code, how can i push the value from <input onChange={this.inputValue} type="text"/> in list : ['car','map', 'house']. I use for this addValue function, but i can't insert the x variable from inputValue function in push() from addValue function. How to do this using my code?
You need a state value for the text-input so that your addValue() function knows what to use when its time to add a new item. The text state will be updated with anything the user types.
Working demo: https://codesandbox.io/s/magical-feynman-fze1n
import React from "react";
class Demo extends React.Component {
constructor() {
super();
this.state = {
text: "",
list: ["car", "map", "house"]
};
}
inputValue(e) {
this.setState({
text: e.target.value
});
}
addValue() {
const text = this.state.text;
this.setState({ list: [...this.state.list, text] });
}
render() {
return (
<div>
<input onChange={this.inputValue.bind(this)} type="text" />
<ul>
{this.state.list.map(item => (
<li>{item}</li>
))}
</ul>
<button onClick={this.addValue.bind(this)}>Add Element</button>
</div>
);
}
}
export default Demo;
Also, refrain from doing direct state-mutations like this.state.list.push(blah). This is against React principles and can lead to unwanted visual side-effects. If you need to reference an existing state, try to create a copy of it instead. In the case for you list, we use the spread-operator to create a shallow-copy and then added the new item to the array..
Since React is all about small components and reusability consider breaking it up into two separate components... That way, if you need a form anywhere else you can reuse it...
Here is your Demo:
class Demo extends Component {
state = { list: ['car', 'map', 'house'] };
addItem = item => {
this.setState({ list: [item, ...this.state.list] });
};
render() {
return (
<div>
<Form addItem={this.addItem} />
{this.state.list.map((item, index) => (
<div key={index}>{item}</div>
))}
</div>
);
}
}
And here is the Form:
class Form extends Component {
state = { item: '' };
handleChange = event => {
this.setState({ item: event.target.value });
};
handleSubmit = event => {
event.preventDefault();
this.props.addItem(this.state.item);
this.setState({ item: '' });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type='text'
value={this.state.item}
onChange={this.handleChange}
/>
</form>
);
}
}
Live Demo: https://stackblitz.com/edit/react-611uzp
I'm learning React and I'm trying to create a program with React that would take texts from two input fields and bind them. I get the input fields but the onClick function is not working.
Would appreciate if someone could point out what I'm doing wrong.
Example
<div id='root'></div>
<script type="text/babel">
class CombineText extends React.Component {
constructor(props) {
super(props);
this.state = {pretext: '', posttext:'', wholetext: '' };
}
combineText = () => {
this.setState({
wholetext: this.state.pretext + this.state.posttext
});
}
textChanged = (event) => {
this.setState({[event.target.name]: event.target.value});
}
render() {
return (
<div>
<p>{this.state.wholetext}</p>
<input type="text" id="pretext" onChange={this.textChanged} />
<input type="text" id="posttext" onChange={this.textChanged} />
<button onClick={this.combineText}>Press me</button>
</div>
);
}
}
ReactDOM.render(<CombineText />, document.getElementById('root'));
</script>
You need to make two changes,
First: use event.target.id while setting the state on change of input since name attribute is not defined on input
Second: Specify button type to be button since its by default submit and onClick on the submit button refreshes the page. Or else you could write event.preventDefault() in the combineText method to prevent the default submit action behavior
class CombineText extends React.Component {
constructor(props) {
super(props);
this.state = {pretext: '', posttext:'', wholetext: '' };
}
combineText = () => {
this.setState({
wholetext: this.state.pretext + this.state.posttext
});
}
textChanged = (event) => {
this.setState({[event.target.id]: event.target.value});
}
render() {
return (
<div>
<p>{this.state.wholetext}</p>
<input type="text" id="pretext" onChange={this.textChanged} />
<input type="text" id="posttext" onChange={this.textChanged} />
<button type="button" onClick={this.combineText}>Press me</button>
</div>
);
}
}
ReactDOM.render(<CombineText />, document.getElementById('root'));
<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='root'></div>
I am new to React and need some help to my specific situation. I have a top-level app.js where I render
export default class Page extends React.Component {
constructor(props) {
super(props);
this.state = {
currentGuess: '',
historicGuess: '',
result: ''
};
}
handleCurrentGuess(event) {
console.log(event)
this.setState({currentGuess: event.target.value})
}
handleSend() {
console.log(this.state.currentGuess)
}
render() {
return (
<div className="wrapper">
<Header />
<Logic handleCurrentGuess={this.handleCurrentGuess}/>
<Result />
</div>
)
}
}
The component has to be stateful, and I enter the currentGuess value into state.
The <Logic /> looks like this:
export default function Logic(props) {
console.log(props)
return (
<div className="logic">
<form>
<input type="text" onChange={props.handleCurrentGuess}/>
<button onClick={(e) => {
e.preventDefault()
props.handleSend
}}>Send</button>
</form>
</div>
)
}
The issue now is that I cannot find documentation on how to pass both pass the function on to the AND get returned a value from the input. Most docs show onChange via the input directly, but I want to fetch the value ONLY when someone clicks on the submit button (or hits enter). So,
how do I pass the correct function to the child, and how do I get the text value back on button press within the Logic component?
If you want to console.log the state right now (for testing purposes obviously) here is the two problems with your code.
First, you are not passing your handleSend function as a prop to Logic component.
Second, on your button, you are not invoking this handleSend function in your onClick handler.
Here is a working example.
const Logic = props => (
<div className="logic">
<form>
<input type="text" onChange={props.handleCurrentGuess} />
<button onClick={props.handleSend}>Send</button>
</form>
</div>
);
class Page extends React.Component {
state = {
currentGuess: '',
historicGuess: '',
result: ''
};
handleCurrentGuess = event =>
this.setState({ currentGuess: event.target.value })
handleSend = (e) => {
e.preventDefault();
console.log(this.state.currentGuess)
}
render() {
return (
<div className="wrapper">
<Logic
handleCurrentGuess={this.handleCurrentGuess}
handleSend={this.handleSend} />
</div>
)
}
}
ReactDOM.render(<Page />, document.getElementById("root"));
<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="root"></div>
I slightly changed the code. Use some arrow functions so no need to .bind them, remove the unnecessary constructor, use class-fields, etc. I also used the function reference for onClick in the button.
In react, assume I have Input component with prop name = A, B, C.
they are rendered in the order
render() {
return(
<Input name="A" />
<Input name="B" />
<Input name="C" />
);
}
then I change the state of C and A in the order first C then A.
component A and C re rendered in the order first A then C. they are not rendered in the order of state change(C then A)
See the code snippet given below.
I found the out put as
set state of C
set state of B
set state of A
Render of A
Render of B
Render of C
class Input extends React.Component {
componentWillMount() {
this.props.addInput(this);
}
state = {
error: false
}
check() {
console.log("set state of", this.props.name)
this.setState({
error: true
})
}
render() {
console.log("Render of", this.props.name)
return (
<input />
);
}
}
class Hello extends React.Component {
constructor(props) {
super(props);
this.inputs = {};
}
addInput(component) {
this.inputs[component.props.name] = component;
console.log(this.inputs);
}
checkAll() {
const inputs = this.inputs;
Object.keys(inputs).reverse().forEach(name => {
inputs[name].check()
});
}
render() {
return (
<div>
<Input addInput={(c) => this.addInput(c)} name="A"/>
<Input addInput={(c) => this.addInput(c)} name="B"/>
<Input addInput={(c) => this.addInput(c)} name="C"/>
<button onClick={() => this.checkAll()}>click here</button>
</div>
);
}
}
ReactDOM.render(
<Hello initialName="World"/>,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>
This is how JSX is supposed to work by default.
If you want to render components in an order of last state change, you'll have to put all your components either into an array or have a collection of componentName: componentInstance, also having a collection [or an array] of componentName: lastUpdated (or array item form { componentName: string, lastUpdated: Date }) in which you can modify each component's lastUpdated value and then sort your componentName: componentInstance collection or array by the date values.
Then just .map in the JSX.
I want to change the input value according to state. The code below triggers the handleChange() method manually. This works for an input box, but I cannot figure out how to do this to also update a select box.
I tried the following but it didn't work.
ev = new Event("option", { bubbles: true });
el = ReactDOM.findDOMNode(node);
See full code below:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: "random text",
country: "USA"
}
}
handleChange (node, value ) {
if(typeof value === "object") {
this.setState({
country: value.target.value
});
} else {
this.setState({value: 'another random text'})
}
var event = new Event('input', { bubbles: true });
this.myinput.dispatchEvent(event);
}
render () {
return (
<div>
<input value={this.state.value} onChange={(e) => {this.handleChange(e)}} ref={(input)=> this.myinput = input}/>
<select onChange={(e) => {this.handleChange(e)}} name="country">
<option>USA</option>
<option>Mexico</option>
</select>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
Changes:
1. Define a name property same as state variable name with both the fields, input and select.
2. Bind the change function inside constructor:
this.handleChange = this.handleChange.bind(this);
3. Use [] to update the particular state variable in change function and access that state variable name by e.target.name.
4. You are using the controlled input element so ref is not required here, you can access input element value by this.state.value
Check the working snippet:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: "random text",
country: "USA"
}
this.handleChange = this.handleChange.bind(this);
}
handleChange (e ) {
this.setState({[e.target.name]: e.target.value})
}
render () {
return (
<div>
<input name='value' value={this.state.value} onChange={this.handleChange}/>
<select name="country" value={this.state.country} onChange={this.handleChange} >
<option>USA</option>
<option>Mexico</option>
</select>
</div>
)
}
}
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'/>