I have a state like this :
{
textfield: '',
data: [] //huge, used to render elements within the render()
}
When I want to update the textfield value (simple text input), I use this.setState({ textfield: newValue });. The problem is that there is some lag when I write a character in the field because it is re-rendering everything.
Is using shouldComponentUpdate() and deeply check my data object the only way to avoid re-rendering everything? Or is there a better/more efficient way?
Thanks
Am guessing its rerendering the entire component due to the state change on every key.
you could isolate your input element in a separate stateful component, hence only triggering a re-render on itself and not on your entire app.
So something like:
class App extends Component {
render() {
return (
<div>
...
<MyInput />
...
</div>
);
}
}
class MyInput extends Component {
constructor() {
super();
this.state = {textfield: ""};
}
update = (e) => {
this.setState({textfield: e.target.value});
}
render() {
return (
<input onChange={this.update} value={this.state.textfield} />
);
}
}
Related
I have encountered a problem and I am new to react. I wanted to find what is the best way to share react state outside of the same component for updating input value
function async callAjax(makeAjaxRequest){
//some ajax call
updateState();
return false;
}
function updateState() {
//I want to update state here from component and from outside
// component as well i.e call from callAjax function
//I wanted to submit form after state update, Can I pass formRef to
//chaining functions to submit or is there any better way?
}
export class test extends React.Component<testProps> {
constructor(props) {
super(props);
this.state = {
action: ''
}
AjaxRequest = await callAjax(
this.props.makeAjaxRequest
);
updateState();
render() {
<form>
<input type="hidden" value={this.state.action} />
</form>
}
}
I have done research around this found some like react sharedContext(useContext) but useContext is mostly used between different components for sharing data but I wanted inside single component. Can anyone help find best way to solve this problem?
Thanks in advance.
I think you shouldn't update the state of a component outside of the component as this may lead to problems. If you must have updateState outside of the component I think you can add callback which will be run when needed.
function async callAjax(makeAjaxRequest, stateCallback ){
updateState( stateCallback );
return false;
}
function updateState( stateCallback ) {
const newValue = 123
stateCallback( newValue )
}
export class Test extends React.Component<TestProps> {
constructor(props) {
super(props);
this.state = {
action: ''
}
}
AjaxRequest = await callAjax(
this.props.makeAjaxRequest,
( newValue ) => this.setState( newValue )
);
render() {
<form>
<input type="hidden" value={this.state.action} />
</form>
}
}
You can also find concept of Redux interesting.
I'm trying to make some component which data output depends on some external API.
So I have this snippet:
class Parent extends Component {
constructor(props) {
super(props)
this.state = {
somethingFromAPI: ''
}
}
componentDidMount() {
/*
something on axios.get() which updates this.state.somethingFromAPI
which normally can have some time delay till executed
*/
}
render() {
return (
<Child value={this.state.somethingFromAPI} />
)
}
}
class Child extends Component {
constructor(props) {
super(props)
this.state = {
value: this.props.value || ''
}
}
handleChange(event) {
this.setState({
value: event.target.value
})
}
static getDerivedStateFromProps(props, state) {
// if difference
return {
value: props.value
}
}
render() {
return (
<div>
<input value={this.state.value} onChange={this.handleChange.bind(this)} />
</div>
)
}
}
ReactDOM.render(
<Parent />
document.getElementById('app')
);
Seems like this works fine, initializing component, and getting API data, after that, input value seems to be updated, which is what I expect.
Problem that hurts me a lot is if I type something inside input, that will call handleChange, but will also trigger this getDerivedStateFromProps and will replace newer inputed value with that "old" from API.
Is this good way of doing this, maybe I made mistake at start with understanding of how it should be done? Guide me in right direction.
I'm yet pretty new to React.
Generally, need to make form which I can use for new input, or updating existing data (like some posts, etc.), so I can load API data.
Best regards.
Did you consider using shouldComponentUpdate instead if using getDerivedStateFromProps
something like this may solve your problem:
shouldComponentUpdate(nextProps, nextState) {
const { value: nextPropsValue } = nextProps;
const { value: propsValue } = this.props;
const { value } = this.state;
if (nextPropsValue !== propsValue && nextPropsValue !== value) {
this.setState({
value: nextPropsValue
});
}
return value !== nextState.value;
}
Update the answer adding comparison with current props value
I think using getDerivedStateFromProps here may be unnecessary. If you want to prevent a render in certain cases, consider using shouldComponentUpdate https://reactjs.org/docs/react-component.html#shouldcomponentupdate. But it sounds like you basically just need to use your input change handler to keep the state of the input, which you're already doing.
You should also check this article out on why someone shouldn't use getDerivedStateFromProps. It's very informative.
I just update to the react 16.3. I have a value to keep tracking of a value that I need to post to the server. I want to save this.value after some props changed. I found out that a lot of life cycle functions are deprecated. And I cannot save the value into redux before rendered. Could anyone give me a good way to handle it? Thanks.
class Foo extends Component {
constructor(props) {
super(props);
this.value = {};
}
render() {
return (
//some other components
<Bar onChange={value => this.value = value} />
)
}
}
I would most likely handle it with this
class Foo extends Component {
state = {
text: ''
}
render() {
return (
//some other components
<Bar onChange={value => this.setState({text:value})} />
)
}
}
Keep in mind this is ES7 way to do it. A bit cleaner than doing it in constructor(). If you don't use new syntax just initiate state in constructor as,
constructor(props){
super(props)
this.state = {
text: ''
}
}
if you would like to get your hands dirty more with handling value that user is giving could also pass onChange value to own function and setState on there. Many prefer it that way.
e.g.
handleChange = (text) => {
// Some amaizing text manipulation
this.setState({text})
}
render() {
return (
//some other components
<Bar onChange={this.handleChange} />
)
}
and with redux dispatch function
constructor(props) {
super(props)
/**
* Bind funtions
*/
const { dispatch } = props
this.patchReservation = params =>
dispatch(ActionCreators.patchReservation(params))
}
Then you just attach e.g. this.patchReservation to onChange -listener. ActionCreators is one of my import's which contains my Redux action -functions.
Cheers!
I'm using the react to build some input forms.
While all children inputs have and their own states to store values I have no idea how to process the to a parent.
Here's example:
class FormComponent extends Component {
constructor(props) {
super(props);
this.state = {
title: null,
someAmount: null
}
}
render() {
let me = this;
return (
<div>
<TextField
value={me.state.title}
onChange={(proxy, value) => {
me.setState({title: value})
me.hanleChnage();
}
}
/>
<TextField
value={Number.parseFloat(me.state.someAmount)}
onChange={(proxy, value) => {
if (!isNaN(Number.parseFloat(value))) {
me.setState({someAmount: value})
me.hanleChnage();
}
}
}
/>
</div>
)
}
handleChange() {
//Calling the parent
//State here is outdated
this.props.onUpdate && this.props.onUpdate(this.state);
}
}
export default FormComponent;
Or where I can find some example of usage of compex forms with much inputs in react.
Thanks!
Sounds like you need to consider moving some of your state into the parent components. The React docs have a good article about this.
To summarize, you can pass your hanleChnage(); function as a prop to your child components if you declare the function in your parent.
function handleChange() { //do something... }
...
<ChildComponent parentOnChange={this.handleChange.bind(this) />
As your components grow in complexity, you might consider using Redux for state management, thus serving as a single source for all state in your application.
Set a child property, (e.g. callParentProperty) to reference a function in the parent component (e.g. parentFunction).
class ParentComponent extends Component{
parentFunction(parameter) {
console.log("This is the form value");
console.log(parameter);
}
render() {
return <FormComponent callParentFunctionProperty={this.parentFunction.bind(this)} />
}
}
class FormComponent extends Component {
...
handleChange() {
...
let formValue = this.state.someAmount;
this.props.callParentFunctionProperty(formValue);
}
}
I am developing a simple browser app to get some specific data from the user.
I have several components to simplify the proccess of collecting that data, but I am currently rethinking my way of rendering this component.
Basically, i have my main component, which uses state to keep track of which component to render.
I am doing this for almost all of my components.
Also, i also have a function inside the parent component, that i pass to the child component via props, and that is used as a callback to pass the child state to its parent, when that component is no longer useful.
class Main extends React.Component {
constructor(props){
this.state = {
renderA: true,
renderB: false,
childState: null
}
}
collectState(state){
this.setState({
childState: state
});
}
render() {
let content = null;
if(this.state.renderA === true){
content = <ComponentA />
} else {
content = <ComponentB />
}
return(
<div>
{content}
</div>);
}
}
So, using the above example, the child would be something like this
class ComponentA extends React.Component {
constructor(props){
super(props);
this.state = {
stop: false,
usefullInfo: null
}
destroy() {
this.props.collectstate(this.state.usefullInfo)
}
render(){
render something (like a Form) untill this.state.usefullInfo is set;
in that case, set this.state.stop true which will call destroy, passing the usefull information to parent
}
}
So, this method works for me, but i can see clearly that most probably this is not the way to do this.
At this point my question are:
1) how can I stop rendering a component without having to track it with some property like this.state.stop ?
2) if i want to render 2 different components, like in the main component, do I always have to keep a renderA and renderB property on state, to render one or another?
3) is there a better way to pass information from child to parent? i am currently using a callback function passed via props from parent to child, and i am invoking that callback when the component has done its purpose
4) any general suggestions on how to improve the quality of the above code?
Thank you for you help :)!
Your example works fine, but in React it is recommended to lift state up when handling data from multiple children (source). So I would recommend to keep the sate of every children in the parent, and pass props with values and handlers to the children.
Here's a sample app you can check. The form components handle the case you want to implement.
To answer your questions:
The parent component should decide, based on its own state, whether to render a child component or not.
It's not needed to keep variables on state about what component to render. that should be computed in render() based on the parent's state
Yes, callback are the recommended way to pass information to parents
Code quality looks good. You can always do good with tools like prettier or ESlint.
Here's an example:
class Main extends React.Component {
constructor(props) {
this.state = {
stateA: '',
stateB: '',
};
}
handleStateChange(name, value) {
this.setState({
[name]: value,
});
}
render() {
const { stateA, stateB } = this.statel;
const shouldRenderA = !stateA;
if (shouldRenderA) {
return <ComponentA value={stateA} onChange={value => this.handleStateChange('stateA', value)} />;
}
return <ComponentB value={stateA} onChange={value => this.handleStateChange('stateB', value)} />;
}
}
class ComponentA extends React.Component {
render() {
const { value, onChange } = this.props;
return <input type="text" value="value" onChange={onChange} />;
}
}