How to get the value of an input field using ReactJS? - javascript

I have the following React component:
export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
var title = this.title;
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};
The console is giving me undefined - any ideas what's wrong with this code?

There are three answers here, depending on the version of React you're (forced to) work(ing) with, and whether you want to use hooks.
First things first:
It's important to understand how React works, so you can do things properly (protip: it's super worth running through the React tutorial on the React website. It's well written, and covers all the basics in a way that actually explains how to do things). "Properly" here means that you're not writing a web page, you're writing the user interface for an application that happens to be rendered in a browser; all the actual user interface work happens in React, not in "what you're used to from writing a web page" (this is why React apps really are "apps", not "web pages").
React applications are rendered based off of two things:
the component's properties as declared by whichever parent creates an instance of that component, which the parent can modify throughout its lifecycle, and
the component's own internal state, which it can modify itself throughout its own lifecycle.
What you're expressly not doing when you use React is generating HTML elements and then using those: when you tell React to use an <input>, for instance, you are not creating an HTML input element, you are instead telling React to create a React input object that happens to render as an HTML input element when you compile your React app for the web, with event handling that is controlled by React.
When using React, what you're doing is generating application UI elements that present the user with (often manipulable) data, with user interaction changing the state of your application in a way that you define - actions performed by the user may update a component's props or state, which React uses as a signal to generate a new UI representation for changed components, which may cause an update of part of your application interface to reflect the new state.
In this programming model, the app's internal state is the final authority, rather than "the UI your users look at and interact with": if a user tries to type something in an input field, and you did not write anything to handle that, nothing will happen: the UI is a reflection of the application state, not the other way around. Effectively, the browser DOM is almost an afterthought in this programming model: it just happens to be a super convenient UI framework that the entire planet is virtually guaranteed to have access to (but it's not the only one React knows how to work with)
A specific example
So with that covered, let's look how a user interacting with an input element works in React. First, we need to get to having a UI element for the user to interact with:
You wrote a component to manage (i.e. both store and present) some string data for your users, with an onChange function for handling user data.
Your component's rendering code is used by React to generate a virtual DOM that contains an input component (not a DOM <input> element), and binds your onChange handler to that component so that it can be called with React event data (so note that this is not a DOM change event listener, and does not get the same event data that regular DOM event listeners do).
The React library then translates that virtual DOM into a UI users can interact with, and that it will update as the application state changes. Since it's running in the browser, it builds an HTML input element.
Then, your user tries to actually interact with that input element:
Your user clicks on the input element and starts typing.
Nothing happens to the input element yet. Instead, the input events get intercepted by React and killed off immediately.
React turns the browser event into a React event, and calls the onChange function for the virtual DOM component with the React event data.
That function may do something, based on what how you wrote it, and in this case you almost certainly wrote it to update the state of your component with what the user (tried to) type.
If a state update gets scheduled, React will run that state update in the near future, which will trigger a render pass after the update.
During the render pass, it checks to see if the state is actually different, and if so, it generates a temporary second virtual DOM, which it compares to (a part of) your application's virtual DOM, determines which set of add/update/remove operations it needs to perform on you application's virtual DOM so that it looks the same as the new temporary one, then applies those operations and throws away the temporary virtual DOM again.
It then updates the UI so that it reflects what the virtual DOM now looks like.
And after all of that, we finally have an updated DOM on the page the user is actually looking at, and they see what they typed in the input element.
So this is completely different from the regular browser model: instead of the user updating the UI data by typing into a text box first and our code reading "the current value of that text box" to figure out what the state is second, React already knows what the state is, and uses events to update the state first, which leads to a UI update second.
And it is important to remember that all of this happens effectively instantly, so to your user it looks like they typed text into an input element in the same way they would for any random web page, but under the hood things couldn't be more different while still leading to the same result.
So, with that covered, let's look at how to get values from elements in React:
Component classes and ES6 (React 16+ and 15.5 transitional)
As of React 16 (and soft-starting with 15.5) the createClass call is no longer supported, and class syntax needs to be used. This changes two things: the obvious class syntax, but also the thiscontext binding that createClass can do "for free", so to ensure things still work make sure you're using "fat arrow" notation for this context preserving anonymous functions in onWhatever handlers, such as the onChange we use in the code here:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.reset();
}
reset() {
// Always set the initial state in its own function, so that
// you can trivially reset your components at any point.
this.state = {
inputValue: ''
};
}
render() {
return (
// ...
<input value={this.state.inputValue} onChange={evt => this.updateInputValue(evt)}/>
// ...
);
},
updateInputValue(evt) {
const val = evt.target.value;
// ...
this.setState({
inputValue: val
});
}
});
You may also have seen people use bind in their constructor for all their event handling functions, like this:
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
...
}
render() {
return (
...
<element onclick={this.handler}/>
...
);
}
Don't do that.
Almost any time you're using bind, the proverbial "you're doing it wrong" applies. Your class already defines the object prototype, and so already defines the instance context. Don't put bind of top of that; use normal event forwarding instead of duplicating all your function calls in the constructor, because that duplication increases your bug surface, and makes it much harder to trace errors because the problem might be in your constructor instead of where you call your code.
"But then it's constantly making and throwing away functions on rerenders!" and that may be true but you're not going to notice. Nor are your users. If event handler garbage collection is your performance bottleneck, so much has already gone wrong that you need to stop and rethink your design: the reason React works so incredibly well is because it does not update the entire UI, it only updates the parts that change, and in a well designed UI, the time that most of your UI spends not changing drastically outnumbers the time small parts of your UI spend updating.
Function components with hooks (React 16.8+)
As of React 16.8 the function component (i.e. literally just a function that takes some props as argument can be used as if it's an instance of a component class, without ever writing a class) can also be given state, through the use of hooks.
If you don't need full class code, and a single instance function will do, then you can now use the useState hook to get yourself a single state variable, and its update function, which works roughly the same as the above examples, except without the "universal" setState function call and using one dedicated state setter for each value you're working with:
import { useId, useState } from 'react';
function myFunctionalComponentFunction(props) {
const id = useId();
const [input, setInput] = useState(props?.value ?? '');
return (
<div>
<label htmlFor={id}>Please specify:</label>
<input id={id} value={input} onInput={e => setInput(e.target.value)}/>
</div>
);
}
Previously the unofficial distinction between classes and function components was "function components don't have state", so we can't hide behind that one anymore: the difference between function components and classes components can be found spread over several pages in the very well-written react documentation (no shortcut one liner explanation to conveniently misinterpret for you!) which you should read so that you know what you're doing and can thus know whether you picked the best (whatever that means for you) solution to program yourself out of a problem you're having.
React 15 and below, using legacy ES5 and createClass
To do things properly, your component has a state value, which is shown via an input field, and we can update it by making that UI element send change events back into the component:
var Component = React.createClass({
getInitialState: function() {
return {
inputValue: ''
};
},
render: function() {
return (
//...
<input value={this.state.inputValue} onChange={this.updateInputValue}/>
//...
);
},
updateInputValue: function(evt) {
this.setState({
inputValue: evt.target.value
});
}
});
So we tell React to use the updateInputValue function to handle the user interaction, use setState to schedule the state update, and the fact that render taps into this.state.inputValue means that when it rerenders after updating the state, the user will see the update text based on what they typed.
addendum based on comments
Given that UI inputs represent state values (consider what happens if a user closes their tab midway, and the tab is restored. Should all those values they filled in be restored? If so, that's state). That might make you feel like a large form needs tens or even a hundred input forms, but React is about modeling your UI in a maintainable way: you do not have 100 independent input fields, you have groups of related inputs, so you capture each group in a component and then build up your "master" form as a collection of groups.
MyForm:
render:
<PersonalData/>
<AppPreferences/>
<ThirdParty/>
...
This is also much easier to maintain than a giant single form component. Split up groups into Components with state maintenance, where each component is only responsible for tracking a few input fields at a time.
You may also feel like it's "a hassle" to write out all that code, but that's a false saving: developers-who-are-not-you, including future you, actually benefit greatly from seeing all those inputs hooked up explicitly, because it makes code paths much easier to trace. However, you can always optimize. For instance, you can write a state linker
MyComponent = React.createClass({
getInitialState() {
return {
firstName: this.props.firstName || "",
lastName: this.props.lastName || ""
...: ...
...
}
},
componentWillMount() {
Object.keys(this.state).forEach(n => {
let fn = n + 'Changed';
this[fn] = evt => {
let update = {};
update[n] = evt.target.value;
this.setState(update);
});
});
},
render: function() {
return Object.keys(this.state).map(n => {
<input
key={n}
type="text"
value={this.state[n]}
onChange={this[n + 'Changed']}/>
});
}
});

Managed to get the input field value by doing something like this:
import React, { Component } from 'react';
class App extends Component {
constructor(props){
super(props);
this.state = {
username : ''
}
this.updateInput = this.updateInput.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
updateInput(event){
this.setState({username : event.target.value})
}
handleSubmit(){
console.log('Your input value is: ' + this.state.username)
//Send state to the server code
}
render(){
return (
<div>
<input type="text" onChange={this.updateInput}></input>
<input type="submit" onClick={this.handleSubmit} ></input>
</div>
);
}
}
//output
//Your input value is: x

You should use constructor under the class MyComponent extends React.Component
constructor(props){
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
Then you will get the result of title

In react 16, I use
<Input id="number"
type="time"
onChange={(evt) => { console.log(evt.target.value); }} />

Give the <input> a unique id
<input id='title' ...>
and then use the standard Web API to reference it in the DOM
const title = document.getElementById('title').value
No need to continually update the React state with every keypress. Simply get the value when it's required.

In Function Component
useState
Returns a stateful value, and a function to update it.
During the initial render, the returned state (state) is the same as the value passed as the first argument (initialState).
The setState function is used to update the state. It accepts a new state value and enqueues a re-render of the component.
src ---> https://reactjs.org/docs/hooks-reference.html#usestate
useRef
useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.
src ---> https://reactjs.org/docs/hooks-reference.html#useref
import { useRef, useState } from "react";
export default function App() {
const [val, setVal] = useState('');
const inputRef = useRef();
const submitHandler = (e) => {
e.preventDefault();
setVal(inputRef.current.value);
}
return (
<div className="App">
<form onSubmit={submitHandler}>
<input ref={inputRef} />
<button type="submit">Submit</button>
</form>
<p>Submit Value: <b>{val}</b></p>
</div>
);
}

In Function Component :-
export default function App(){
const [state, setState] = useState({
value:'',
show:''
});
const handleChange = (e) => {
setState({value: e.target.value})
}
const submit = () => {
setState({show: state.value})
}
return(
<>
<form onSubmit={()=>submit()}>
<input type="text" value={state.value} onChange={(e)=>handleChange(e)} />
<input type="submit" />
</form>
<h2>{state.show}</h2>
</>
)}

export default class App extends React.Component{
state={
value:'',
show:''
}
handleChange=(e)=>{
this.setState({value:e.target.value})
}
submit=()=>{
this.setState({show:this.state.value})
}
render(){
return(
<>
<form onSubmit={this.submit}>
<input type="text" value={this.state.value} onChange={this.handleChange} />
<input type="submit" />
</form>
<h2>{this.state.show}</h2>
</>
)
}
}

I succeeded in doing this by binding this to the function
updateInputValue(evt) with
this.updateInputValue = this.updateInputValue.bind(this);
However input value={this.state.inputValue} ...
turned out to be no good idea.
Here's the full code in babel ES6 :
class InputField extends React.Component{
constructor(props){
super(props);
//this.state={inputfield: "no value"};
this.handleClick = this.handleClick.bind(this);
this.updateInputValue = this.updateInputValue.bind(this);
}
handleClick(){
console.log("trying to add picture url");
console.log("value of input field : "+this.state.inputfield);
}
updateInputValue(evt){
//console.log("input field updated with "+evt.target.value);
this.state={inputfield: evt.target.value};
}
render(){
var r;
r=<div><input type="text" id="addpixinputfield"
onChange={this.updateInputValue} />
<input type="button" value="add" id="addpix" onClick={this.handleClick}/>
</div>;
return r;
}
}

your error is because of you use class and when use class we need to bind the functions with This in order to work well. anyway there are a lot of tutorial why we should "this" and what is "this" do in javascript.
if you correct your submit button it should be work:
<button type="button" onClick={this.onSubmit.bind(this)} className="btn">Save</button>
and also if you want to show value of that input in console you should use var title = this.title.value;

This simplest way is to use arrow function
Your code with arrow functions
export default class MyComponent extends React.Component {
onSubmit = (e) => {
e.preventDefault();
var title = this.title;
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={(c) => this.title = c} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};

React Version: 17.0.1
a) Using Functional Components
b) Manage state using hook: useState().
Write and Run code as above:
import React, {useState} from 'react';
const InputElement = () => {
const [inputText, setInputText] = useState('');
return (
<div>
<input
onChange={(e) => {
setInputText(e.target.value);
}
}
placeholder='Enter Text'
/>
{inputText}
</div>
);
}
The solving scheme algorithm is similar to a two-way data binding:
input <=> DATA_MODEL <=> Label_Text

// On the state
constructor() {
this.state = {
email: ''
}
}
// Input view ( always check if property is available in state {this.state.email ? this.state.email : ''}
<Input
value={this.state.email ? this.state.email : ''}
onChange={event => this.setState({ email: event.target.value)}
type="text"
name="emailAddress"
placeholder="johdoe#somewhere.com" />

You can get an input value without adding 'onChange' function.
Just add to the input element a 'ref attr:
And then use this.refs to get the input value when you need it.

Change your ref into: ref='title' and delete name='title'
Then delete var title = this.title and write:
console.log(this.refs.title.value)
Also you should add .bind(this) to this.onSubmit
(It worked in my case which was quite similar, but instead of onClick I had onSubmit={...} and it was put in form ( <form onSubmit={...} ></form>))

if you use class component then only 3 steps- first you need to declare state for your input filed for example this.state = {name:''}. Secondly, you need to write a function for setting the state when it changes in bellow example it is setName() and finally you have to write the input jsx for example < input value={this.name} onChange = {this.setName}/>
import React, { Component } from 'react'
export class InputComponents extends Component {
constructor(props) {
super(props)
this.state = {
name:'',
agree:false
}
this.setName = this.setName.bind(this);
this.setAgree=this.setAgree.bind(this);
}
setName(e){
e.preventDefault();
console.log(e.target.value);
this.setState({
name:e.target.value
})
}
setAgree(){
this.setState({
agree: !this.state.agree
}, function (){
console.log(this.state.agree);
})
}
render() {
return (
<div>
<input type="checkbox" checked={this.state.agree} onChange={this.setAgree}></input>
< input value={this.state.name} onChange = {this.setName}/>
</div>
)
}
}
export default InputComponents

export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
var title = this.title.value; //added .value
console.log(title);
}
render(){
return (
...
<form className="form-horizontal">
...
<input type="text" className="form-control" ref={input => this.title = input} name="title" />
...
</form>
...
<button type="button" onClick={this.onSubmit} className="btn">Save</button>
...
);
}
};

using uncontrolled fields:
export default class MyComponent extends React.Component {
onSubmit(e) {
e.preventDefault();
console.log(e.target.neededField.value);
}
render(){
return (
...
<form onSubmit={this.onSubmit} className="form-horizontal">
...
<input type="text" name="neededField" className="form-control" ref={(c) => this.title = c}/>
...
</form>
...
<button type="button" className="btn">Save</button>
...
);
}
};

Related

How to prevent re-rendering of components that have not changed?

I have a component that consists of several other components such as text fields, and when an input is made to the text field, all other components are re-rendered.
I would like to prevent the re-rendering and only re-render the component that actually changes.
I have seen that useCallback is the right way to do this and I have already seen how to use it. However, I'm having some trouble getting useCallBack to work correctly for my case.
Even if I set it up in a simple manner as below, each new character entered into the text field causes the button to be rendered again.
I don't see my mistake.
See working example in sandbox.
const Button = () => {
console.log("Button Rendered!");
window.alert("Button Rendered");
return <button onClick="">Press me</button>;
};
export default function App() {
const [textInput, setTextInput] = useState("Hallo");
const onChangeInput = useCallback(
(e) => {
setTextInput(e.target.value);
},
[textInput]
);
return (
<div>
<input
type="text"
onChange={onChangeInput}
value={textInput}
/>
<Button />
</div>
);
}
I am happy for any calrification.
Personally I would avoid React.memo / React.useRef / React.useCallback.
The simplest solution to your example is just create another component, and store the state with this.
eg.
const Button = () => {
console.log("Button Rendered!");
window.alert("Button Rendered");
return <button onClick="">Press me</button>;
};
const TextInput = () => {
const [textInput, setTextInput] = useState("Hallo");
const onChangeInput = useCallback(
(e) => {
setTextInput(e.target.value);
},
[textInput]
);
return (
<input
type="text"
onChange={onChangeInput}
value={textInput}
/>
);
}
export default function App() {
return (
<div>
<TextInput/>
<Button />
</div>
);
}
In the above if you change Text, there is not State change in App, so Button doesn't get re-rendered, no need for useMemo etc..
You will find React works really well, the more you divide your components up, not only does it solve issues of re-render, but potentially makes it a lot easier to re-use components later.
IOW: keep state as close to the component as possible, and performance will follow.
Of course your example is simple, and in a real app you will have HOC's etc to cope with, but that's another question.. :)
useCallback does not prevent rerenders. React.memo is what prevents renders. It does a shallow comparison of the previous props with the new props, and if they're the same, it skips rendering:
const Button = React.memo(() => {
console.log("Button Rendered!");
window.alert("Button Rendered");
return <button onClick="">Press me</button>;
});
The only role that useCallback plays in this is that sometimes you want to pass a function as a prop to a memoized component. For the memoization to work, props need to not change, and useCallback can help the props to not change.
changing the state causes re-render component along with all his heirs, to prevent re-render some sections, you can use useMemo to prevent unwanted re-rendering...
NOTE: useMemo has some costs... so don't overuse it (In this small example, it is not recommended at all).
in this case, if you do not need to re-rendering, you can use the useRef to save the input reference to get that value whenever you need it.
e.g:
const BlahBlah = () => {
const inputRef = React.useRef(undefined);
return (
<div>
<input ref={inputRef} />
<button onClick={() => console.log(inputRef.current.value)}
</div>
);
};
I had similar problem. I wanted to avoid rendering a component which dependent on part2 of state, when only part1 has changed.
I used shouldComponentUpdate(nextProps, nextState) as described here https://reactjs.org/docs/optimizing-performance.html to avoid rendering it.
I'm using it this way:
const [state_data, set_state_data] = useState([
true, // loading.
{}, // vehicle.
{} // user.
]);
This allows rendering only 1x instead of 3x and React keeps track of the changes. For some reason it won't track the change of objects, but arrays yes.

How to add event to react function and re-render function

I have a function that renders content to page based on a state populated by API data, but I need to have an onClick event to refine that content;
So currently getPosts returns information from the state 'posts' which is provided with data from our API, but i want to filter this content further, so my idea is to have some sort of event listener, and if actioned, change the data coming out of getPosts.
constructor() {
super();
this.state = {
posts: ""
}
this.getPosts = this.getPosts.bind(this);
}
async componentWillMount(){
var data = await api.posts();
this.setState({posts: data.data});
console.log(this.state.posts);
}
getPosts(type){
if(this.state.posts.length){
return this.state.posts.map((content,index) => {
var url = content.Title.replace(/[^\w\s]/gi, '');
url = url.replace(/\s+/g, '-').toLowerCase();
if(type === content.PostType){
//output something different
}
else{
return(
<Col md={4} className="mb-4" key={index}>
{content.title}
</Col>
);
}
})
}
}
render() {
return (
<div>
<p><button onClick={()=>{this.getPosts('blog')}}>blog</button> <button onClick={()=>{this.getPosts('news')}}>news</button></p>
{this.getPosts()}
</div>
)
}
So my getPosts works fine without any type, how to do tell it to re-output the function on the page based in the onClick event?
Without getting into the complexities of context and keys, a component requires a change in props or state to re-render. To read more about state and component life-cycle, the docs have a great explanation for class components.
Your component does not re-render after the onClick event handler's call to getPosts because getPosts does not update internal component state. getPosts works within render because those values are being returned to React. By using getPosts as an onClick event handler, you are creating React elements and trying to return them to the window.
What follows should be treated as psuedo code that shows how to trigger your component to render different posts:
Consider adding another key to state in your constructor,
constructor(props) {
super(props);
this.state = {
posts: "",
type: null
};
this.getPosts = this.getPosts.bind(this);
this.onClick = this.onClick.bind(this);
}
and creating a click handler that doesn't try to return React elements
function onClick(evt) {
this.setState({ type: evt.target.value });
}
and values to your buttons
<button onClick={this.onClick} type="button" value="blog">blog</button>
Now your button will update state with your new post type, causing your component to re-render:
render() {
return (
<div>
<p>
<button onClick={this.onClick} type="button" value="blog">blog</button>
<button onClick={this.onClick} type="button" value="news">news</button>
</p>
{this.getPosts()}
</div>
);
}
With the content type being stored in state, you can now implement your getPosts call in any way that works for you. Good luck!
It strays from the question asked, but it is worth noting componentWillMount is being deprecated, and componentDidMount is a preferable life-cycle function for side-effects and asynchronous behavior. Thankfully, the documentation has lots of details!
Ok so you should start by changing your default this.state to
this.state = {
posts: []
}
remember that you want to iterate over an array of data instead of iterate a string, that will throw an error if you do that, so better keep from the beginning the data type you want to use.
Then you need to separate the responsibility for your getPosts method, maybe getPostByType is a better name for that, so you have
getPostByType(type) {
// if type is same as content.PostType then return it;
const nextPosts = this.state.posts.filter((content) => type === content.PostType);
this.setState({ posts: nextPosts });
}
and finally you can iterate over posts, like this
render() {
// better use content.id if exists instead of index, this is for avoid problems
// with rerender when same index key is applied.
const posts = this.state.posts.map((content, index) => (
<Col md={4} className="mb-4" key={content.id || index}>
{content.title}
</Col>
));
return (
<div>
<button onClick={() => this.getPostByType('blog')}>Show Blog Posts</button>
{posts}
</div>
);
}
Then you can use getPostsByType any time in any click event passing the type that you want to render.

Pasing fetched data as props (a JSON) to state in order to render data

Currently I get my data from an API in a JSON-format when running my saga. The fetching process begins, when the component did mount. That means the component renders two times.
Now, when the data is available as props. I can use it in order to render it.
My approach to this is like following, I have got a:
Constructor with the initial state
I fetch data in "componentDidMount"
I got a function that takes the JSON properties from props and puts it into new variables
I run this function in my render() function, when the props contain the fetched data
The Problem in this approach: Once the component runs the function where the data becomes "structured", the render-function loops and then after some time, the values of the properties get displayed with a warning message in the console.
My Questions:
How to prevent the looping when render() runs once?
How can I design this, so that particular properties of the fetched object merge into a new object and how to
I hope I described the most important things about my issue. Here is the code:
class Dashboard extends React.Component {
constructor(props) {
super(props);
this.state = {
deviceInfo: {
name: "Initial Name",
batLevel: "78%",
}
}
}
componentDidMount() {
this.props.requestApiData();
}
updateDeviceInfoWithState (){
const devices = (this.props.data.data);
if(devices){
const newDeviceInfo = this.state.deviceInfo;
newDeviceInfo.name = devices[0].shadow.desired.payload.refAppData.name;
newDeviceInfo.batLevel = devices[0].shadow.reported.payload.refAppData.batteryState.level;
this.setState({
deviceInfo: newDeviceInfo,
});
}
}
render() {
this.updateDeviceInfoWithState()
return (
<div className='container'>
<p> {this.state.deviceInfo.name} </p>
<p> {this.state.deviceInfo.batLevel} </p>
</div>
)
}...
Updating the state in the render method is not a good practice, since it might cause an infinite loop.
In your case state is redundant, since you only take the data from props, or replace it with defaults. Instead of using the state return the name and batLevel in the updateDeviceInfoWithState method, and use it in the render method.
Example (not tested):
class Dashboard extends React.Component {
componentDidMount() {
this.props.requestApiData();
}
updateDeviceInfoWithState (){
const devices = this.props.data.data;
if(devices){
const device = devices[0].shadow;
return {
name: device.desired.payload.refAppData.name,
batLevel: device.reported.payload.refAppData.batteryState.level
};
}
return {
name: "Initial Name",
batLevel: "78%",
};
}
render() {
const { name, batLevel } = this.updateDeviceInfoWithState();
return (
<div className='container'>
<p> {name} </p>
<p> {batLevel} </p>
</div>
);
}...
Note 1: If you want to decouple your component from the state, it's better to enforce simple properties as input for the data. For example, this component needs as properties the name and batLevel. It doesn't need to be aware of the array of devices, shadow, payload, etc... You can prepare the data when you receive it in the saga, or use a redux selector in mapStateToProps.
Note 2: If you really need the data in your state, you can use the getDerivedStateFromProps life-cycle method (React 16.3), or update the state in the componentWillReceiveProps if you use an older version.
For this case you can use ComponentWillRecieveProps method like this
componentWillRecieveProps(nextProps) {
// Condition as per ur requirement.
If(this.props.data != nextProps.data) {
this.updateDeviceInfoWithState(nextProps)
}
}
This method will only run whenever ur component props are changed.

Pass value from class method to a react component

Situation: I have a class with its own methods. This class is instantiated in a React component.
What I'm needing: During one of the methods in the class, it changes the value of an input (this.$el) using .val(), but I'm listening to changes to this input in the React.component via onChange. I need to pass the value I'm using to set the value of the input (via this.$el.val(value)) to the React component to change its state.
What I've tried: I've tried chaining .change() and trigger('change') to the val(value), but it doesn't have any affect.
So, I need to be able to access the value I'm using in .val(value) in my React component WHEN it is set in the class method. I thought about using a method and calling that method on componentWillUpdate, but the component doesn't update since setting the input value via val() doesn't trigger a change.
Any ideas?
Component code:
// Create a ref to manage blur/focus state on the search input
this.inputRef = React.createRef()
// Setup initial state
this.state = {
supersearchResults: [],
value: this.props.initialValue || ''
}
this.onInputChange = this.onInputChange.bind(this)
tag('input', {
autoComplete: 'off',
className: blockElement('search-input'),
onChange: this.onInputChange,
placeholder: 'Find people, collections and pages',
ref: this.inputRef,
type: 'text',
value: this.state.value
})
Class code:
this = class
this.$el = input
// What is happening:
// A user types in an input, suggestions display in a list, when you
// select a suggestion, it calls the below to change the input value
this.$el.val(complete)
this.$el.blur()
this.hide()
If I understand correctly, you want to be able to access the value of a html field. Then please take into consideration the following considerations. Use controlled inputs such that the
class ReactComponent extends...
constuctor (props) {
super();
this.state = { fieldValue: props.fieldValue || '' };
}
onFieldChange = (event) => {
this.setState('fieldValue': event.currentTarget.value)
}
render () {
return (
<div>
<input type="text"
value={this.state.fieldValue}
onChange={this.onFieldChange}
>
<div>
)
}
}
Now having this code, in case you need to use some external class to call some code, simply put it correctly in the lifecycle. But in order to reference the value use the components state. And in case you want to programmatically want to change the value, do the same update the value in the state. If I missed something let me know in the comments.
You need to keep the state in your class component. consider the following
class TextExample extends Component{
constructor(){
super(props);
this.state ={
username: null
}
this._handleChange = this._handleChange.bind(this);
}
_handleChange(e){
const { name, value } = e.target;
this.setState({ username: value}) // for single TextField
// if you want to reuse this _handleChange function for all the TextFields then you need to use the below commented code which updates state of current TextField
//this.setState({ [name]: value }) // it is similar like the JSON bracket notation
}
render(){
return(
<div>
<TextField
id="username"
label="Username"
name="username"
value={this.state.username}
onChange={this._handleChange} // it will call the _handleChange function on every keypress inside the TextField.
/>
</div>
)
}
}

render checkbox and update data in react

I'm stuck changing the array of object value of checkbox. I'm even not sure my current approach is correct or not, because I have no clue what to do next. Assume fruits data is an ajax call, it's should come from componentWillMount right? should I set the state like this.setState({input:ajaxresponse})? I'm lost, it's hard for me because I was using jquery. Just now I also read about redux, I heard people said in redux you don't use setState, omg I'm lost.
http://jsbin.com/dodanahani/1/edit
class HelloWorldComponent extends React.Component {
constructor(){
super()
this.handleChange = this.handleChange.bind(this);
this.state = {
input: {}
}
}
handleChange(e,key){
console.log(e.target.checked)
// how to update state here?
}
render() {
const data = {
"fruits":[
{"name":"banana","value":true},
{"name":"watermelon","value":false},
{"name":"lemon","value":true},
]
}
return (
<div>
{data.fruits.map(obj =>
<div key={obj.name}>
<label>{obj.name}</label>
<input onChange={(e) => this.handleChange(e, obj.name)} type="checkbox" defaultChecked={obj.value} />
</div>
)}
<p>{this.state.fruits}</p>
</div>
);
}
}
What I want to achieve is simple : user get api data, and he know his previously saved data, bind to view (checkboxes), and he can update them again. I'm stuck at sending back the changes.

Categories

Resources