I am currently building a weather web app with React, and now I have a question: How do I change my components (SaveWeather) city-value?
Say that you clicked on a button where you entered 'Berlin', and the code below runs. The this.state.value is 'Berlin', and I want to add SaveWeather component with this value. But if I enter my next value, say 'London', The this.state.value is still 'Berlin'. So I want to update the city-value of SaveWeather every time the user enters new information.
test() {
this.setState({
saveWeather: [this.state.saveWeather, <SaveWeather city={this.state.value} key="1" />]
});
}
Thanks in advance!
You shouldn't really save components in your state, only data. The way I'd do this would be something like this.
Your state:
{value: "Initial Value that can be an empty string"}
A function that handles the value changes:
handleValueChange(e) {
// e is the event that comes from the input element (where the user writes the city they want)
const city = e.target.value;
this.setState({value: city})
}
Then, in your render:
render() {
return <div>
<input onChange={this.handleValueChange} value={this.state.value}/>
<SaveWeather city={this.state.value} />
</div>
}
You should try to understand this code, don't just copy it. Any question drop a comment below ;)
Related
Having a hard time seeing how I could accomplish this. I created some custom number buttons from 0-9 that users can click on instead of using the keyboard. The problem I'm having is I have multiple dynamically created input fields depending on JSON Data so let's say there are 10 dynamically created input fields and a user starts with question one and the user then uses the custom number buttons I created and clicks numbers "145" to answer question one, but what happens is then all 10 inputs have the same number "145" not the problem the user was trying to solve. I'm using the context API to then save the values typed in on a function called getButtonValue that I then call to the parent component and save the values in a state array, so I know that my problem is that all the inputs share the same state array but how could I make sure the correct input the user clicks on is only receiving those values.
Thanks in advance.
My Custom Number Button Component:
import { FormContext } from "../../lib/FormContext";
function ActivityBar() {
const { getButtonValue } = useContext(FormContext);
return (
<div className={`${activity.activity__workSheet__numberButton}`}>
<button value={0} onFocus={(e) => getButtonValue(e)}>
<img
className={`${activity.activity__workSheet__img0}`}
src={"/assets/activityNumber-btn.png"}
alt="activity number button"
/>
.... more code
Parent Component:
const [numberButtonClicked, setNumberButtonClicked] = useState([]);
const getButtonValue = (e) => {
setNumberButtonClicked((prevButtonClicked) => [
...prevButtonClicked,
e?.target?.attributes[0].value
]);
};
return (
<Carousel>
<div ref={imageRef} style={{ height: "100%" }}>
{Object.entries(elements).map((element, i) => {
const { fields } = element[1];
if (fields) {
return (
<Element
key={i}
field={fields[0]}
id={i}
useReff={`answer${i}`}
currentValue={
numberButtonClicked === "" ? null : numberButtonClicked.join("")
}
/>
);
} else {
return;
}
})}
</div>
</Carousel>
Got a good working version figured out for this scenario, what I did was.
I have a onFocus method on my input tags that then takes in the event and calls a handleChange(e) function. Within that function I then save the currentInputId in a variable by using e?.target?.attributes[0]?.value and the previous InputId in a state variable and just check if the previous InputId is equal to the currentId user just focused on. If so then we'll add the next number user clicks into the same field, else if previousInputId !== currentInputId then make my user value state array empty, setNumberButtonClicked([]).
I am working on Update Task activity, and I am not able to edit content in Textbox as it has been derived from this.props.location.state.****.
Please suggest. How I can keep it editable.
Code :
<textarea ref="taskdescr" type="text" class="form-control" value={this.props.location.state.tskDescr} id="taskDesc"></textarea>
This is normal because when you provide value props in react.
The textarea will gain the value your provided after each render.
So because the value of your props does not change when you edit the textarea, the provided value is always the same.
To make your textarea editable your need to use the state instead of props.
If i understand what you want to do your state can look like site
{
tskDescr: '',
proptskDescr: '',
}
Use getDerivedStateFromProps and update tskDescr when proptskDescr is not equal to props.location.state.tskDescr.
And add an onChange event on the textarea to update the tskDescr
You need to change the value on the state using onChange for the textarea as follows
constructor(props){
super(props);
this.state = {
location: {
tskDescr: ''
}
}
}
And then
handleChange = (event) => {
this.setState({
location: {
tskDescr: event.target.value
}
});
}
Props are immutable use state if you want to mutate the values, after adding the state you need to provide a listener so that you can change the value.
<textarea
value={this.state.text}
onChange={this.handle}
/>
handle = ({target:{value}}) => this.setState({text:value});
I'm trying to implement the Google Tasks Add Task feature (See pic for reference). Basically, when you click on Add Task button, it opens an input field which autosaves as you type. I'm trying to implement this in React.js.
class App extends Component {
state = {
showInput: false,
addTaskInput: ''
}
showAddTask = (e) => {
this.setState({showInput: true})
}
saveInput = (e) => {
this.setState({addTaskInput: e.target.value})
}
render() {
const {showInput, addTaskInput} = this.state;
return (
<div className="app">
<Button
message="Add Task"
bsStyle="primary"
onClick={this.showAddTask}
/>
{ showInput && <input
type="text"
placeholder="Add Task here..."
value={addTaskInput}
onChange={this.saveInput}
/> }
<TodoList addItem={}/>
</div>
);
}
}
Here is my code. App is my main component. TodoList is the component which has the whole list of Todos. What I am going to do is:
When I type something in the input, it fires onChange and sets the state. Inside onChange I would also change the addItem prop which would re-render TaskList. This doesn't seem very optimal because of unnecessary re-renders. I'm thinking of changing addItem prop when focus on input is removed.
How do I go about doing the latter? Alternative approaches are welcome.
I would say it depends on how much your app is doing; if it's just a simple app saving onChange is not bad, but if a lot else is going on, yeah you should optimise.
onBlur
mix keystroke and debounce (my favorite)
when input is more than a set length
Currently, I can only change the value of the input field through the spinner buttons.
But when I click inside the input to type in a number manually, the text cursor goes away and I'm unable to type inside. I can click on the input box WHILE typing, and that would work though. Below is a simplification of my React code:
constructor(props) {
super(props)
this.state = {
quantity: 1
}
}
//This is just making some API call, but am I supposed to do anything else here to update the value?
handleQuantityChange(e) {
this.props.editQuantity({
quantity: e.target.value
})
}
render() {
return (
<input type="number" value={this.state.quantity} onChange={this.handleQuantityChange.bind(this)}
)
}
The numbers are reacting correctly, but only to the spinner buttons.
The input is a controlled component, which means its value will always be that in the value prop. You can either switch to an uncontrolled component by using defaultValue, or update the state on every change so that the value can update.
this.setState({
quantity: e.target.value
})
I have a React (15.3.2) component with a text input.
(Everywhere I say "render" here it's actually render or unhide; I've tried both.)
When that input element is blurred, I render a new component with a text input.
I want give the new text input focus.
I've tried componentDidMount, componentWillUpdate, and componentDidUpdate; I've tried named and function refs; I've tried react-dom.
The focusing itself works, e.g., once it's been rendered, if I click in the initial input, focus goes to the new input (this is a bug, but compared to focusing, trivial).
The first input has an onBlur that sets the state used to tell the second input to render or not.
In that blur handler I stop the event as best as I can.
When I tab out of the first element I'm already "past" the newly-rendered element, e.g., the browser tab bar in my current bare design–I guess the new element hasn't been rendered yet?
class SecondInput extends Component {
componentDidUpdate = (prevProps, prevState) => {
if (!this.props.hidden) this._input.focus()
}
render = () =>
<input type="text" hidden={this.props.hidden} ref={(c) => this._input = c}
}
class NewItem extends Component {
state = { itemEntered: false }
itemBlurred = (e) => {
e.preventDefault()
e.stopPropagation()
this.setState({ itemEntered: true })
}
render = () =>
<div>
Item: <input type="text" onBlur={this.itemBlurred} />
<SecondInput hidden={!this.state.itemEntered} />
</div>
}
Any ideas or hints? I have to believe it's something obvious, because surely this happens all the time.
I'm also open to any other form of component hierarchy, e.g., if I need to have a container that wraps all this stuff up somehow that's fine.
React 15.3.2
The problem you are seeing appears to be because there are no more focusable elements on the page when you press tab, so the focus goes to the address bar. For some reason when the focus is on the address bar, just calling this._input.focus() does not grab focus as you would expect.
In order to combat this problem, I have added an empty div, and set the tabIndex property based on whether or not the second input is shown.
Just to make things easier for myself, I made the input focus on mount instead of using the hidden property. This may or may not work in your case, but it seemed to be cleaner since it would keep the input from calling focus on every keypress if it were to be a controlled input.
let Component = React.Component;
class SecondInput extends Component {
componentDidMount(){
this.textInput.focus()
}
render(){
return (
<input type="text" ref={(input) => this.textInput = input} />
)
}
}
class NewItem extends Component {
state = { itemEntered: false }
itemBlurred = (e) => {
//e.preventDefault()
//e.stopPropagation()
this.setState({ itemEntered: true })
}
render = () =>
<div>
Item: <input type="text" onBlur={this.itemBlurred} />
{
this.state.itemEntered ? [
<SecondInput/>
] : []
}
<div tabIndex={this.state.itemEntered ? null : 0}/>
</div>
}
ReactDOM.render(<NewItem />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.3.0/react-dom.min.js"></script>