How to maintain state - reactjs

I have a text box with some text which I get after doing ajax call.
When ever a user keys some text I dispatch the value to state.
This renders the current text area and cursor goes to front of the line.
How can I avoid re-rendering. How should I maintain state.
class Design extends React.Component{
constructor(){
super();
}
handleMessageChange(e){
let msg = e.target.innerText;
this.props.dispatch({type:'design_changed',designObj:{property:'message',value:msg}})
}
render(){
return (
<React.Fragment>
<Panel header="Message" key="2">
<div>
<div className="userscoop-content-editable-cls" contentEditable="true" onKeyUp={this.handleMessageChange.bind(this)}>{this.props.message}</div>
</div>
</Panel>
</React.Fragment>
}
function mapStateToProps(state){
let settings = state.HelloBar.template.settings;
return {
background_color: settings.background_color,
action_color:settings.action_color,
message:settings.message,
button_color:settings.button_color,
input_placeholder:settings.input_placeholder,
goal:state.HelloBar.goal
}
}

If you use shouldComponentUpdate lifecycle method and compare the new and old state you can cancel the render.
Alternatively you could first try PureComponent and see if that works.
If you still have problems might consider looking into saving the cursor state also. [from here]

You can use components's shouldComponentUpdate() method to define whether or not it should rerender when some prop changes. You can write to to ignore this change.

Try Redux-Form,if you are dealing with components which requires continuous action on fields.
Or use document.addEventListener in every actions which you fire by passing keyUp or keyDown

Related

How to use state in dynamically created components at runtime for React Native

I have created a function that creates and builds a tree of components at run time.
This tree is different every time based on some parameters coming from a webservice.
I am able to render the tree successfully, but the state values don't get updated when the state is changed.
For example:
export default class App extends React.Component {
state={
loading:true,
}
componentDidMount() {
this.buildComponent();
}
buildComponent() {
var comp = <View style={{flex:1,justifyContent:'center',alignItems:'center'}}>
<Text>{this.state.name}</Text>
<Button title="Change State" onPress={()=>this.setState({name:"Changed"})} />
</View>
this.comp = comp;
this.setState({loading:false});
}
render() {
if (this.state.loading) {
return <Text style={{alignSelf:'center',marginTop:50}}>Loading ...</Text>
}
return (
this.comp
);
}
}
In this code sample, I know it is not best practice to do it this way, but I just have a use case in which I need to code it in such way.
As you see in the sample, when I click on the button, I want the state name to be changed to "Changed", but it doesn't get changed.
Sounds like React doesn't map the state.name inside the text and renders it once it's changed.
I don't want to place the buildComponent inside render method because buildComponent does a lot of expensive calculations and calling it every time would affect the performance big time, therefore I wanted a way to build the components one time and render it, but state values don't get updated at all.
Thanks in advance for your valuable input.
u are using componentDidMount so the comp only renders once when the state is updated componentDidMount is not called, so if u want to reRender comp again u def componentDidUpdate instead
componentDidUpdate() {
this.buildComponent();
}

Relations setState and child component

I made some app to get asynchronously data from remote server.
The app just parent component - to get data, and two child components.
One child component for display asynchronous data.
Other child for filter functionality. Just input string where user typing and data in first component display appropriate items.
There are a lot code with console.log everywhere, but in simple scheme it:
class App extends Component {
state = {isLoading:true, query:''}
getData = (location) => {
axios.get(endPoint).then(response=>{ response.map((item) => { places.push(item)})
// ***** first setState
this.setState({isLoading:false})
})
}
updateQuery = (e) => {
// ***** second setState
this.setState({query:e.target.value.trim()})
}
componentDidMount(){
this.getData(location)
}
render() {
if (!this.state.isLoading){
if (this.state.query){
const match = new RegExp(escapeRegExp(this.state.query),'i')
searchTitles = places.filter(function(item){return match.test(item.name)})
}else{
searchTitles = places.slice();
}
}
return (
<div className="App">
<input type='text' onChange={this.updateQuery} value={this.state.query}/>
<List places = {searchTitles}/>
</div>
);
}
}
export default App;
When state change in case of using everything is OK - content refreshed in next child component.
But child component that display data - some items not full of content... no photos and some text information. So probably its rendered before getting remote data.
But why its not re-render it after state.isLoad toggled to 'false' (in code - after got response) ?
I put among code console.log to track processes ... and weird things: state.isLoad switched to false before some part of data came from server. (((
I dont use ShouldComponentUpdate() inside child component.
Per React's documentation for setState
setState() will always lead to a re-render unless
shouldComponentUpdate() returns false.
As mentioned, one way to avoid a re-render is shouldComponentUpdate returning false (shouldComponentUpdate takes in nextProps and nextState) but it's not clear why someone would trigger a state change with setState and then nullify that state change with shouldComponentUpdate.

How to change state of component from anywhere without Redux?

Is this bad practices or not ?
export state change function from component
import it from other file.
call the function to change state?
In this way we can change some component state from anywhere.
For example...
We want to change the Model.js state from anywhere.
Modal.js
import React from 'react';
export let toggleModal;
export default class Modal extends React.Component {
constructor(props) {
super(props);
this.state = {
open: false,
};
toggleModal = this.toggleModal;
}
toggleModal = () => {
this.setState({ open: !this.state.open });
};
render() {
const { open } = this.state;
return <div style={{ color: 'red' }}>{open && 'Hello Modal'}</div>;
}
}
App.js(Some Top Level component)
import React from 'react';
import Modal from './Modal';
export default () => (
<>
...
<Modal />
...
</>
);
Somewhere.js
import React from 'react';
import {toggleModal} from './Modal';
export default () => (
<>
<h1>Hello!</h1>
<button onClick={() => toggleModal()}>open Modal!</button>
</>
);
  
But there is no reference in React Official docs, so is this bad practices ?
What React Docs recommends...
Just passing function props to change parent state from parent to children
Use context
Redux or Mobx
But, these are too complex for me.
Example code here
https://next.plnkr.co/edit/37nutSDTWp8GGv2r?preview
Everything seems pretty much overwhelming and difficult at the beginning. But as we get out hands on them, it's give us more confidence to dig into.
I would recommend to use redux that's how we tackled props drilling problem. You can dispatch a action and connect reducer to corresponding component which upon updating state will re render. This is what I recommend to most of the people to learn the tale of redux with a real life example:
Understanding Redux: The World’s Easiest Guide to Beginning Redux
Apart from this you can take Dan Abramov, author of the library, free redux course on egghead.io:
Getting Started with Redux
The problem you run into, almost immediately like your code example does is this:
It will not work: your toggleModal() method expects a this to refer to an actual component instance. When your onClick() handler fires you invoke toggleModal() as a plain function. The this context will be wrong, and so at best (in your example) you will get an error because you try to invoke something undefined, at worst (in general) you end up invoking the wrong method.
When you think about it, for any non-trivial React component you will have a hard time obtaining a reference to the actual instance that is currently being used: you have to make sure that you are not forgetting to invoke the method on the right component instance and also you have to consider that instances may be created/destroyed 'at will' for whatever reason. For example: what if your component is rendered indirectly as part of some other component's render() method? Multiple layers of indirection like that make it even harder.
Now, you could fix all that by abusing ref with abandon but you will find that now you have to keep track of which ref refers to what particular instance, if you happen to have multiple of the components to consider in one render tree...
Whenever you think one component needs to handle the state of its siblings, the solution is usually to lift the state one level up.
export default class Modal extends React.Component {
render() {
const { isOpen } = this.props;
return <div style={{ color: 'red' }}>{isOpen && 'Hello Modal'}</div>;
}
}
export default class Home {
this.state = {
isOpen: false,
};
toggleModal = () => {
this.setState({ isOpen: !this.state.isOpen });
}
render() {
const { isOpen } = this.state;
return (
<>
<h1>Hello {name}!</h1>
<button onClick={() => this.toggleModal()}>open Modal!</button>
<Modal isOpen={isOpen}/>
<p>Start editing and see your changes reflected here immediately!</p>
</>
)
}
}
This way the Home handle the state and your problem is solved.
This can get annoying if the state needs to be "drilled down" to children, that's a problem than redux or react-context can solve.
Here <Modal /> is the child component. So to call a function in a child component you can simply use Ref.
You can refer this page to get more info about Ref.
You can assign a class variable as a ref to this child and use this class variable as an object to call its function.
I found if in special case, my way is okay.
Special case means something like customAlert component.
It is okay only one instance of customAlert component mounted at a time in App.
To achieve this...
1.Use ref to access and change DOM
2.attach state changing function or component to window and call window.function
3.my case: export state changing function and import it from other file.
And here is how to do with react Context
https://next.plnkr.co/edit/EpLm1Bq3ASiWECoE?preview
I think Redux is overkill if the main thing you are interested in is to make some states-like data available and updatable throughout your App without props drilling.
For that purpose, a much simpler approach (maybe not available at the time the question was posted?) is to use react context: https://frontend.turing.edu/lessons/module-3/advanced-react-hooks.html
"context - an API given to us by React, allowing for the passing of
information to child components without the use of props
[...]
useContext - a react hook, allowing functional components to take
advantage of the context API"

child component update parent component

I just wonder if it is good that the child component updates the parent component.
in the source code, like following
class Parent extends React.Component{
state = {
name : ''
}
changeState = ((state) => {
this.setState(state)
})
submit = (() => {
// send state to api..
})
render(){
return(
<div>
<Child changeState={this.changeState} {...this.state}/>
<button onClick={this.submit} />
</div>
)
}
}
class Child extends React.Component{
change = ((e) => {
this.props.changeState({
name : e.target.value
})
})
render(){
return(
<input onChange={this.change} value={this.props.name} />
)
}
}
the reason I use this way is submitting method.
There are many input tags, and I want to bind them all together.
but I'm not sure this way is good or not.
because when I type something, parent component always will rerender.
I think it is not good.(actually it just my thinking...)
is it right?
I have used this way to update state of a parent from a child. It does work properly. But it makes the components little complex.
In your case (assuming you do this for text input elements) I don't think this will be a good practice if you are doing it for tiny input components. Because every time you hit a key on a keyboard the parent component will try to update.
But if you are wrapping a set of input elements and pass a larger object to a parent component I think that will be fine.
You could use react life cycle method shouldComponentUpdate() method to control the rendering of the parent component
shouldComponentUpdate
https://reactjs.org/docs/react-component.html#shouldcomponentupdate
shouldComponentUpdate(nextProps, nextState) {
if (this.props.name != nextProps.name) {
return true;
} else {
return false;
}
}
Here nextProps refers to the props you receive(updates) and you can refer to current prop values by "this.props"
And return true to render and false to skip the rendering.
If you have perform validations when the user inputs, then its ok.
Otherwise change 'onChange' event to 'onBlur'
Its a good idea to lift the state up and update it in the parent if multiple other siblings want to refer to the same values. You can optimise on this my making your Parent and Child Components pure as long as they don't have complex and deeply nested props and states.
According to the React docs:
React.PureComponent is exactly like React.Component, but
implements shouldComponentUpdate() with a shallow prop and state
comparison. If your React component’s render() function renders the
same result given the same props and state, you can use
React.PureComponent for a performance boost in some cases.
Re-rendering of parent is not a problem as long as it is not wasted. And Unless you are using Redux, I think this is a proper way to manage the state, i.e., inside the parent component and updating it using the child. In this way, you have made your form into a controlled component.
I think the following page will be useful to you: https://scotch.io/courses/getting-started-with-react/parent-child-component-communication

Can someone give proper explanation for ref vs controlled input and use case for state variable in react?

I went through the docs of react, about controlled and uncontrolled components. I have created a simple use case where I want to enforce the user to enter only uppercase values in the input field.
In the first case I have used 'ref' with 'onChange' to achieve this and a global object's property to capture the dom node.Here's the code for that -
https://jsfiddle.net/69z2wepo/78064/
class Nikhil extends React.Component {
constructor(props){
super(props);
this.field = {
input: ''
};
}
foo() {
this.y = this.field.input;
this.y.value = this.y.value.toUpperCase();
}
render() {
return (
<div>
<input ref={ node => this.field.input = node } onChange={ this.foo.bind(this) }/>
</div>
);
}
}
ReactDOM.render(<Nikhil/>,container);
In the second case I have used 'value' property and state with'onChange'.
Here's the code for that -https://jsfiddle.net/69z2wepo/78066/
class Nikhil extends React.Component {
constructor(props){
super(props);
this.state = {
input: ''
};
}
foo(e) {
this.setState({ input: e.target.value.toUpperCase() });
}
render() {
return (
<div>
<input value= { this.state.input } onChange={ this.foo.bind(this) }/>
</div>
);
}
}
ReactDOM.render(<Nikhil/>,container);
The docs says:
With a controlled component, every state mutation will have an
associated handler function. This makes it straightforward to
modify or validate user input. For example, if we wanted to enforce
that names are written with all uppercase letters, we could write
handleChange as:
handleChange(event) {
this.setState({ value: event.target.value.toUpperCase()} );
}
Well I can validate the user input even when I am not using state, and not syncing the value prop with state , as done in the first example above.
So definitely validating user input can be done without using state at all ?
Can you explain why one approach is better than the other ?
What exactly the 'single source of truth' means and why it is so important ?
In both the cases I am using a global variable of the component which is an object and can be accessed throughout the component.
Also why should I unnecessarily use value = { this.state.input } in example 2, because that would call render on every keystroke, whereas in case 1 render is called only once. So isn't performance in case 1 better than 2 ?
Also from the docs:
To write an uncontrolled component, instead of writing an
event handler for every state update, you can use a ref to get
form values from the DOM
Well I need to write an event handler like 'onChange' even when using 'ref' to validate user input at run time as done in case 1. So using event handler with 'ref' is normal ?
Use case for state variable -- From my understanding the only case where I have no other option than to use state variable is when I need to update the view dynamically. Because this.setState() calls render every time it is run .
Here's the code for that -https://jsfiddle.net/69z2wepo/78068/
class Nikhil extends React.Component {
constructor(props){
super(props);
this.state = {
input: ''
};
}
foo(e) {
this.setState({ input: e.target.value });
}
render() {
return (
<div>
<input onChange={ this.foo.bind(this) }/>
<p>{ this.state.input }</p>
</div>
);
}
}
ReactDOM.render(<Nikhil/>,container);
I will be grateful if someone could clarify on all the three examples and enhance my understanding of the above concepts.
According to React Docs - https://facebook.github.io/react/docs/refs-and-the-dom.html:
Don't Overuse Refs
Your first inclination may be to use refs to "make things happen" in your app. If this is the case, take a moment and think more critically about where state should be owned in the component hierarchy. Often, it becomes clear that the proper place to "own" that state is at a higher level in the hierarchy
In rare cases, you might want to have access to a child's DOM node from a parent component. This is generally not recommended because it breaks component encapsulation, but it can occasionally be useful for triggering focus or measuring the size or position of a child DOM node.
I think the general idea is that, if you are using React, you should use what react does better, that is the state manipulation using setState.
Use ref method to create a new item of a collection via submit. Let's assume you have a MongoDB collection called cars. If you want to add a car via form submission you should use the ref method.
Use value (onChange) method to edit an existing item: Let's assume you want to change the price of your car collection for certain car. You mirror the state with the input, so by typing, you also change the state at the same time.
React's official docs do recommend the second method, but you cannot change a value of an item that doesn't exist, so in these cases the first method is the appropriate one.

Resources