Live updates between React components based on state - javascript

My (simplified) goal:
Show a form input's text content beside the form itself and update the reflected text as the input text changes. The form lives within a React component, and the displayed text lives inside another one.
I can use the component state to control the input's text and change the state based on onChange form event. But how can I also change the state of the displayed text so that I get the live updates I'm looking for?
Input and output components have the same parent component.
Here's my input component:
import React, { useState } from "react";
function InputBoxTest() {
const [inText, setInText] = useState("");
const handleChange = event => {
setInText(event.target.value);
// My instinct is to setOutText here, but I can't...
};
return (
<textarea className="form-control" id="comment" onChange={handleChange}>
{inText}
</textarea>
);
}
export default InputBoxTest;
My output component:
import React, { useState } from "react";
function OutputBoxTest() {
const [outText, setOutText] = useState("");
return <p>{outText}</p>;
}
export default OutputBoxTest;
And my parent component:
import React from "react";
import InputBoxTest from "./InputBoxTest";
import OutputBoxTest from "./OutputBoxTest";
function Test1(props) {
return (
<>
<div className="row">
<div className="container-fluid col-sm-7">
<InputBoxTest />
</div>
<div className="col-sm-5">
<OutputBoxTest />
</div>
</div>
</>
);
}
export default Test1;

You could move the State Hook from InputBoxText into the ParentComponent Test1
InputBoxText is then used for displaying and updating the state
OutputBoxText is used for displaying only
import React from "react";
import InputBoxTest from "./InputBoxTest";
import OutputBoxTest from "./OutputBoxTest";
function Test1(props) {
const [inText, setInText] = useState("");
const handleChange = event => {
setInText(event.target.value);
};
return (
<>
<div className="row">
<div className="container-fluid col-sm-7">
<InputBoxTest text={inText} handleChange={handleChange} />
</div>
<div className="col-sm-5">
<OutputBoxTest text={inText}/>
</div>
</div>
</>
);
}
export default Test1;
function InputBoxTest(props) {
return (
<textarea className="form-control" id="comment" onChange={props.handleChange}>
{props.text}
</textarea>
);
}
export default InputBoxTest;
function OutputBoxTest(props) {
return <p>{props.text}</p>;
}
export default OutputBoxTest;

If you need to share some state between 2 components, you need to move that state in their (at least first) parent. You can read more about it here.
Basically what this means is that your Test1 component should be holder of your textarea value.
Please see this example based on your code.

Related

Detect focus on children component with react

I have a parent component and in general I render input fields inside it.
is there a way to know if the children input has focus?
<Component>
<input />
</Component>
const Component = (props) => return (<div className="nice">{props.children}</div>)
I've created a sandbox that you can check here : https://codesandbox.io/s/chris-lisangola-c53ri-c53ri
From the link that you've posted i seems like the main problem is the way to handle event triggered from a child component to the parent through props.If i'm wrong please let me know.
I've created a child component like this :
import React from "react";
export default function Input(props) {
const { checkFocus } = props;
return <input onFocus={checkFocus} />;
}
And in the child component i've added a event listener of type focus that is passed to the parent through the checkFocus.
In the parent component App:
import React, { useState } from "react";
import FormInput from "./FormInput";
import "./styles.css";
export default function App() {
const [text, setText] = useState("");
const checkFocus = (e) => {
console.log(e.type);
if (e.type === "focus") {
setText("Focus");
}
};
return (
<div className="App">
<h1>Handle Focus : {text}</h1>
<FormInput checkFocus={checkFocus} />
</div>
);
}
I've done a very basic test so that of there is a focus in the child's input , the text Focus is displayed in the h1 tag

How to display JSX returned from other function inside return?

I'm trying to build a weather application using openweathermap api. As you can see below in the code, I use a boolean state to check when the form is summitted so I can pass that value to the <Result> component(which I checked with hard code and it works). I want the function changeCity(in the App) to return the <Result> component with the value of city passed and in the same time to change the cityEmpty state. But there I got the problem when I pass that in the return() {(cityEmpty) ? changeCity() : null}
import React, {useState} from 'react';
import Result from "./components/Result";
import Search from "./components/Search";
import './App.css';
function App() {
const [city, setCity] = useState ("");
const [cityEmpty, setCityEmpty] = useState(false);
const changeCity = () => {
setCityEmpty(false);
return (<Result city={city}/>);
}
return (
<div className="App">
<Search city={city} setCity={setCity} cityEmpty={cityEmpty} setCityEmpty={setCityEmpty}
/>
{(cityEmpty) ? changeCity() : null}
</div>
);
}
export default App;
import React from "react"
function Search({city, setCity, cityEmpty, setCityEmpty}){
const handleInputChange = (e) => {
setCity(e.target.value);
}
const handleSumbit = (e) => {
e.preventDefault();
console.log(cityEmpty);
setCityEmpty(true);
console.log(cityEmpty);
setCity("");
}
return(
<div>
<form onSubmit={handleSumbit}>
<input
type="text"
placeholder="Insert city"
value={city}
onChange = {handleInputChange}
>
</input>
</form>
</div>
);
}
export default Search
You can't call a state update inside the render of a component. Remember that whenever state is updated, it will re render the component. This will cause an infinite loop in your component.
Component renders
changeCity is called
Inside changeCity, setCityEmpty is called
Go back to step 1 for rendering.
Instead, consider checking if city is empty in your handleInputChange and calling setCityEmpty inside that function.
EDIT: To clarify a function that returns a component is completely fine, this is all components are really. Functions (or in previous react versions: classes) returning other components.
you don't have to return JSX from function. In your case it is pretty straightforward to use.
import React, {useState} from 'react';
import Result from "./components/Result";
import Search from "./components/Search";
import './App.css';
function App() {
const [city, setCity] = useState ("");
const [cityEmpty, setCityEmpty] = useState(false);
return (
<div className="App">
<Search city={city} setCity={setCity} cityEmpty={cityEmpty} setCityEmpty={setCityEmpty}
/>
{cityEmpty && <Result city={city}/>}
</div>
);
}
export default App;
import React from "react"
function Search({city, setCity, cityEmpty, setCityEmpty}){
const handleInputChange = (e) => {
setCity(e.target.value);
}
const handleSumbit = (e) => {
e.preventDefault();
console.log(cityEmpty);
setCityEmpty(true);
console.log(cityEmpty);
setCity("");
}
return(
<div>
<form onSubmit={handleSumbit}>
<input
type="text"
placeholder="Insert city"
value={city}
onChange = {handleInputChange}
>
</input>
</form>
</div>
);
}
export default Search
Not sure what the problem you're seeing is but I noticed you're setting state inside of a render function, which is a bad pattern. Any state changes will trigger a re-rendering of the component and if you set state within a render function then you'd have an infinite loop of re-renderings (but.
Try removing setCityEmpty(false) in changeCity.
const changeCity = () => {
return (<Result city={city}/>);
}
So how would you update cityEmpty? It's not clear what the end goal is here. With more info, we can find a better implementation.

Is there any way to re-render the component on onchange event on checkBox

Here i am trying to change the style of the text to line trough onchange event but the component did not rerender and the style didn't change.
import React from 'react';
import {useDispatch} from 'react-redux'
import {DelAction,CompleteAction} from '../Action'
function Todo(props) {
//assigning dipsatch
const dispatch=useDispatch();
//Delete the Todo form the store
const getStyle=()=>{
return{
textDecoration:props.todo.completed?'line-through':'none',
backgroundColor:'rgb(20%,50%,60%)',
borderBottom:'1px #000 dotted',
}
}
return (
<div style={getStyle()} >
<p style={{fontSize:'20px'}}>
<input type="checkbox" onChange={()=> dispatch(CompleteAction(props.todo.id))}/>
<button style={{float:'right'}} onClick={ () => dispatch(DelAction(props.index) )} >Delete</button>
</p>
</div>
);
}
export default Todo;

How to get label values dynamically and adding the numbers together from different input with reactjs

Created a Div and inside it I have label element and input element, I want to get different label values in each div. How to re-use my div component
instead of coding the same code again.
I have tried to search in Stackoverflow plus googles, Haven't received a better answer.
Here I have created div element with just label and input element and then I have rendured this component in App.js file:
How can I reuse the same code/component to create 2 more div and having different labels values in it? Ho can I add numbers together from different input ( which I am getting from different components input)
Appreciate all your help!
import React, { Component } from 'react';
import './calculator.css';
class Boxes extends Component {
state = {
inputOne: '',
inputtwo: '',
inputthree: ''
}
getInputValue = (e) => {
const value = e.target.value;
console.log('value: ', value);
this.setState({
inputOne: Number(e.target.value)
});
}
render() {
const { value } = this.props // destructuring
const {inputOne, inputtwo, inputthree } = this.state
return (
<div className="boxes">
<label className="boxeslevel" htmlFor="text">
{value}
</label>
<input
name="text"
type="text"
onChange={this.getInputValue}
/>
</div>
);
}
}
export default Boxes;
import React, { Component } from 'react';
import './App.css';
import Boxes from './components/calculator';
class App extends Component {
render(){
return (
<div className="wrapper">
<Boxes value= {"Value 1:"} onChange={this.props.onChange}/>
<Boxes value= {"Value 2:"} onChange={this.props.onChange}/>
<Boxes value= {"Value 3:"} onChange={this.props.onChange}/>
<ShowResult />
</div>
);
}
}
export default App;
You should pass a prop to your componente to be reuse. As you notice you are using local component state in your component, like const {value} = this.state try the same approach but with props like const {value} = this.props and then passing that prop in the component usage like
<Boxes value={“label 1”}/>
<Boxes value={“label 2”}/>
That would work. Hope it help you
Remember you can use as many props you need and access them as the same way mention above
You can do something like this:
class Boxes extends Component {
render() {
const { value } = this.props // value coming from props
return (
<div className="wrapper">
<div className="firstBox">
<label htmlFor="text">
{value}
</label>
<input name="text" type="text" />
</div>
</div >
);
}
}
export default Boxes;
and in your app component something like this:
import React, { Component } from 'react';
import './App.css';
import Boxes from './components/calculator';
class App extends Component {
render(){
return (
<div className="App">
<Boxes value={1}/>
<Boxes value={2}/>
<Boxes value={3}/>
</div>
);
}
}
export default App;
Here is live demo link
You have to use props instead of state in your Boxes component. Then you can pass the required props from the App component.
App.js
import React, { Component } from 'react';
import './App.css';
import Boxes from './components/calculator';
class App extends Component {
render(){
return (
<div className="App">
<Boxes value={"Value 1"}/>
<Boxes value={"Value 2"}/>
<Boxes value={"Value 3"}/>
</div>
);
}
}
export default App;
Boxes.js
import React, { Component } from 'react';
import './calculator.css';
class Boxes extends Component {
render() {
const { value } = this.props // destructuring
return (
<div className="wrapper">
<div className="firstBox">
<label htmlFor="text">
{value}
</label>
<input name="text" type="text" />
</div>
</div >
);
}
}
export default Boxes;

React Select with Redux React form

I am trying to integrate react-select with react redux form (https://github.com/davidkpiano/react-redux-form)
This is my current component set up and I am passing props to it from another component.
...
<MultiSelect model="event.category" options={this.props.categoryList} />
...
Multi select component
import React, {Component} from 'react';
import {Control} from 'react-redux-form';
import Select from 'react-select';
import 'react-select/dist/react-select.css';
class MultiSelect extends Component {
constructor(props) {
super(props);
this.state = {categoryValue: []};
}
handleSelectChange = value => {
this.setState({categoryValue: value});
};
render() {
let reactSelect = props => (
<Select
{...props}
/>
);
return (
<div className="form__row">
<div className="form__label">
<span className="form__title">
{this.props.title}
{this.props.isRequired ? (
<span className="form__required">*</span>
) : (
''
)}
</span>
</div>
<Control.custom
model={this.props.model}
id={this.props.model}
component={reactSelect}
simpleValue
multi
value={this.state.categoryValue}
options={this.props.options}
onChange={this.handleSelectChange}
joinValues
name={this.props.model}
required
/>
</div>
);
}
}
export default MultiSelect;
My problem is that I can't seem to grab the value of that hidden text field in my react redux form state. What could I be missing?
Here is the code sandbox too https://codesandbox.io/s/ww4wqyp02l
From the documentation;
If you do not want any standard property mappings (such as onChange,
onBlur, etc.) passed down to your custom control component, use
and define your own mappings:
<Control.custom
component={SpecialCustomText}
mapProps={{
onTextChange: (props) => props.onChange,
onLoseFocus: (props) => props.onBlur,
// etc.
}}
/>
Also, you needed a submit button on which you can retrieve the value from the MultiSelect component that you've made.
I've made changes to reflect these changes on your codesandbox here

Categories

Resources