Send data from child component to parent component in react js - javascript

I have a dropdown menu by using Semantic-UI CSS Framework. I want to select an item on drowdown menu and know which item selected. I can know which is selected and set state in child component but I cannot send parent component. Actually I sent it by using callback function but it happened loop and exceed memory while setting parent's state. I followed this way for that.
My parent component is "SorguView" and also child component is "DropDownItem"
Thanks for helps.
Sorgu Class:
export class Sorgu {
_id:string;
userName:string;
anaSorgu:string;
aciklama:string;
sName:string;
constructor(id:string, username:string, anaSorgu:string, aciklama:string, sName:string) {
this._id = id;
this.userName = username;
this.anaSorgu = anaSorgu;
this.aciklama = aciklama;
this.sName=sName;
}
}
Interface SorguProps:
export interface SorguProps {
sorgu:Sorgu;
}
Interface SorguProps:
export interface SorguStates {
sorguList:Array<Sorgu>;
selectedName:string;
}
DropDownItem component (child):
class DropdownItem extends React.Component<SorguProps,SorguStates> {
constructor(props: SorguProps, context: any) {
super(props, context);
this.state = {
selectedName: 'no-data'
} as SorguStates;
this.calis = this.calis.bind(this);
}
calis = () => {
this.setState({selectedName: $('.item.active.selected').text()},() => console.log(""));
}
render() {
console.log("states",this.state);
console.log("props",this.props);
this.props.myFunc(this.state.selectedName);
return (
<div className="item" data-value={this.props.id} onClick={this.calis}>
{this.props.name}
</div>
);
}
}
SorguView (Parent):
export class SorguView extends React.Component<SorguProps,SorguStates> {
constructor(props: SorguProps, context: any) {
super(props, context);
this.state = {
sorguList: [],
selectedName:''
} as SorguStates;
this.hello=this.hello.bind(this);
}
hello(data){
console.log("data=>"+data);
//this.setState({selectedName: data} as SorguStates); //Exceed memory
console.log("=>>>>"+ this.state.selectedName);
}
render(){
return (
<div className="ui selection dropdown" ref="dropSorgu">
<input type="hidden" name="selSorgu"/>
<div className="default text">Seçiniz</div>
<i className="dropdown icon"></i>
<div className="menu">
<DropdownItem name={this.state.sorguList[0].sName} id={this.state.sorguList[0].sName} myFunc={this.hello} />
</div>
</div>
);
}
}

Children components should be "dumb" and should not alter the state of the component. They should simply be passed props and pass data back to the parent if the state needs to be altered.
You are passing the hello function as a prop myFunc which is correct. Dropdown item should then call that function and pass it the necessary data so that way the parent can set the state of the selected item.
calis = () => {
this.props.myFunc($('.item.active.selected').text());
}
This will call the hello function in the parent component and then you can set the state from there.

Related

Troubles with state

I'm just started to learn react, and i have a question
Well, i can impact on state from one component to another. But can i do it in reverse?
Here's what i mean:
import React from 'react';
import Butt from './Button';
class Checkbox extends React.Component {
constructor(props) {
super();
}
render() {
return (
<div>
<Butt arg={13} />
</div>
);
}
}
export default Checkbox;
import React from 'react';
class Butt extends React.Component {
constructor(props) {
super();
this.state = {
s1: props.arg,
};
}
add = () => {
let val = this.state.s1;
val++;
this.setState({ s1: val });
};
render() {
return (
<div>
<label>
<label>
<button onClick={this.add}>add</button>
<div>{this.state.s1}</div>
</label>
</label>
</div>
);
}
}
export default Butt;
Sorry for my silly question. Thanks in advance :)
I am not sure about your question, but in react, there is a one-way flow (from parent to child) for transferring information (props, states, or ...). If you want to have access to states everywhere or set them in each direction you should use Redux or context or any other state management.
You're updating the Butt state from inside Butt so this will work fine. It won't change the value of this.props.arg though, if that's what you're asking.
Props are always non-mutable.
What you can do is have two components share the state of their parent...
class Parent extends React.Component {
state = {
val = 0
}
render () {
return (
<>
<Child1
val={this.state.val}
onChange={newVal => this.setState({ val: newVal })}
/>
<Child2
val={this.state.val}
onChange={newVal => this.setState({ val: newVal })}
/>
</>
)
}
}
Then inside the child components pass the updated value to onChange...
class Child1 extends React.Component {
handleChange() {
this.props.onChange(this.props.val + 1)
}
render() {
return (
<Button onClick={() => this.handleChange()}>
Update value
</Button>
)
}
}
This way you're just passing a new value from Child to Parent and letting Parent decide what to do with it.
Whether Child1 or Child2 sends the new value, both children will get updated when Parent calls this.setState({ val: newVal }) and changes this.state.val.

Best way to access state of a React child class component in React parent functional component (react-dual-listbox)

I tend to use react functional components and hooks as I do not have a lot of experience with react. I want to use the react-dual-listbox class component within a parent functional component. Within this parent component I want to be able to access the selected state of the child class component. What is the best way to do this?
Child react-dual-listbox component from https://github.com/jakezatecky/react-dual-listbox
import React from 'react';
import DualListBox from 'react-dual-listbox';
const options = [
{ value: 1, label: 'Option One' },
{ value: 2, label: 'Option Two' },
];
class DualListChild extends React.Component {
state = {
selected: [1],
};
onChange = (selected) => {
this.setState({ selected });
};
render() {
const { selected } = this.state;
return (
<DualListBox
options={options}
selected={selected}
onChange={this.onChange}
/>
);
}
}
Contained within a standard functional component
function Parent() {
return(
<div>
<DualListChild/>
</div>
)
}
export default Parent;
Is it possible to, for example, have a hook in the parent component that changes state corresponding to what the dual listbox has selected? Essentially I want to pass state up but to a functional component? Is there a way to do this?
Thanks
You'd do something similar to what you do in DualListChild, except using the useState hook instead:
class DualListChild extends React.Component {
onChange = (selected) => {
this.props.onSelected(selected);
};
render() {
return (
<DualListBox
options={options}
selected={this.props.selected}
onChange={this.onChange}
/>
);
}
}
function Parent() {
const [selected, setSelected] = React.useState();
return (
<div>
<DualListChild selected={selected} onSelected={setSelected} />
</div>
)
}
Now you have access to selected (and even setSelected) inside your Parent component.
As an alternative way, you can have another state that keeps track of selected options in the parent and send its setter function to the child. Whenever the state of the child is changed, call the setter function that is coming from parent. With that way, the selected options state will be up-to-date value for the child and parent components any time.
function Parent() {
const [selectedOptions, setSelectedOptions] = useState([]);
return(
<div>
<DualListChild onSelectedOptionsChange={setSelectedOptions}/>
</div>
)
}
export default Parent;
class DualListChild extends React.Component {
...
onChange = (selected) => {
this.setState({ selected });
props.onSelectedOptionsChange(selected);
};
...
}

how to update parent's state from child component along with passing some information from child

I am trying to build a portal where I have 3 components.
Parent component
->Child 1
->Child 2
From main component
-if (no files are selected) then GUI should show just the Child 1 and
Count and pathnames of files associated with Application
-else if (user has clicked on any file) then GUI should show the filename and
nodes associated to it.
I am trying to achieve this but i am confused in how to pass info from parent to child and vice versa.
In the code given below in Child 1.js when user click on path, the Parent component should update the GUI view by calling Child2 rather than calling Child1 .
How can i achieve this?
For update parent component state from child component with arguments. You need to create method in parent component, that set state from arguments from this method. And pass this method to child component by props.
class Parent extends React.Component {
state = {text: ""}
updateText = text => {
this.setState({text: text})
}
render () {
return (<Child updateText={this.updateText}>)
}
}
class Child extends React.Component {
render () {
return (
<button
onClick={
() => this.props.updateText("updated state from child component")
}
>Update State</button>
)
}
}
Building on what galishmann provided, just pass y.Filename to the function in props as it already expects a vlaue as a parameter.
class Parent extends React.Component {
state = { text: "" }
updateText = text => {
this.setState({ text: text })
}
render() {
return (<Child updateText={this.updateText} />)
}
}
class Child extends React.Component {
....
....
....
render() {
const { updateText } = this.props;
const pathElement = this.state.groupedByAppName.map((x) => {
return (
<Collapsible trigger={x.AppName + '\t' + x.Count + ' files'} transitionTime={20}>
{
x.section.map((y) => <p filename={y.FileName} onClick={() => updateText(y.Filename)}>{y.Path}</p>)
}
</Collapsible>
)
})
return <div> {pathElement} </div>
}
}

Updating child Components with state change in Reactjs

So I know this question has been asked a couple of times and the general concession is that props cant be changed when it has already passed down to a child. The situation I have here is that basically i have a different onClick function in a different file that updates the the id="movie-header" with an innerHTML, the DOMSubtreeModified and componentDidUpdatedetects the change and pass down the new props to Child "Ebay".
So the question here is how do I get the Ebay component to update its state and make use of the new value with every change to the state in the moviemodalwindow(the parent of the Ebay)
MovieModalWindow.js
import React from "react";
import "../MovieGo.css";
import Ebay from "../Store/Ebay";
class MovieModalWindow extends React.Component {
constructor() {
super();
this.state = {
name: 1
};
}
componentDidMount() {
var element = document.getElementById("movie-header");
element.addEventListener("DOMSubtreeModified", this.myFunction(element));
var name = this.state.name + 1;
this.setState({ name: [...this.state.name, name] });
}
myFunction = input => event => {
this.setState({ name: input.innerHTML });
};
componentDidUpdate(prevProps, prevState) {
if (prevState.name != this.state.name) {
window.localStorage.setItem("keyword", this.state.name);
}
}
render() {
return (
<div id="myModal" class="modal">
<div class="modal-content">
<span onClick={onClose} class="close">
×
</span>
<h1 id="movie-header" />
<div className="middle-window">
<div className="left">
<Ebay id="ebay" keyword={this.state.name} />
</div>
</div>
<h3>PLOT</h3>
<p id="moviedetails" />
</div>
</div>
);
}
}
export default MovieModalWindow;
Ebay.js File
import React from "react"
class Ebay extends React.Component{
constructor(){
super();
this.state={
data:[],
}
}
componentWillUpdate(prevProps, prevState){
if (prevProps.keywords!=this.props.keywords){
console.log(window.localStorage.getItem("keyword"))
}
render(){
const{newInput} =this.props
return(
<div>
</div>
)
}
}
export default Ebay
I'm unsure if I'm answering the question you're asking, so apologies if this isn't what you're asking.
Step 1. Make Ebay's prop's change when you need this update to happen. (I think you stated you already have this occurring?)
Step 2: Make Ebay's state update when the props change. Here you can just watch for prop changes with componentWillReceiveProps and update the state accordingly.
class Ebay extends React.Component {
constructor() {
super();
this.state = { data: [] };
}
componentWillRecieveProps(nextProps) {
if (nextProps.keyword !== this.props.keyword) {
this.setState({ data: ['something new'] });
}
}
render() { ... }
}

React Component not updating with state change

I currently have a reducer that does a deep copy of state and returns it with the updated value.
function countableItems(state = initialState, action) {
switch (action.type) {
case types.ADD_TO_SUM:
let denomMap = findDenomination(state.denomGroups, action),
nestedCopy = Immutable.fromJS(state);
return nestedCopy.setIn(['denomGroups', denomMap.group, denomMap.key, denomMap.index, 'sum'], parseFloat(action.value)).toJS();
default:
return state;
}
}
In my render function of the display Component I see the correct updated values in this.props.denoms The render() function builds up child <DenomInput> components, and when I set my breakpoints I see the correct data being passed in
render() {
let denomGroups = this.props.denoms.map((denom, i) => {
return (
Object.keys(denom).map((key) => {
let denoms = denom[key].map((item, i) => {
return <DenomInput denom={item} onDenomChange={this.onDenomChange} key={i}></DenomInput>
});
return (<div className="col"><h2>{key}</h2>{denoms}</div>)
})
);
});
return (
<div className="countable-item-wrapper">
<div className="row">
{denomGroups}
</div>
</div>
);
}
However when the <DenomInput> components render it renders the same value as what they were initially set
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class DenomInput extends Component {
constructor(props) {
super(props);
this.state = { denom: props.denom }
this.handleKeyUp = this.handleKeyUp.bind(this);
}
handleKeyUp = (e) => {
this.props.onDenomChange(e.target.value, this.state.denom.name);
}
render() {
return (
<div className="input-group denom">
<span className="input-group-addon">{this.state.denom.label}</span>
<input
type="text"
className="form-control"
onChange={this.handleKeyUp}
value={this.state.denom.sum} />
<span className="input-group-addon">{this.state.denom.count | 0}</span>
</div>
);
}
}
DenomInput.PropTypes = {
denom: PropTypes.object.isRequired,
onDenomChange: PropTypes.function
}
export default DenomInput;
What piece am I missing to update the view with React and Redux?
May be componentWillReceiveProps can do the trick. It will update the state of the component whenever new data is receive from parent, and call the render function again.
Try
class DenomInput extends Component {
...
componentWillReceiveProps(nextProps) {
this.setState({ denom: nextProps.denom })
}
...
}
It looks like you're seeding your initial state with the props from your store. You then render from the component state, but you never update the component state. They only get set once because constructor is only called once the component is rendered. To fix, either remove this component state entirely and just connect it to the redux store, or update the component state onChange. I recommend removing the local state. I have found that keeping the two states in sync is error-prone.
constructor(props) {
super(props);
this.state = { denom: props.denom }
this.handleKeyUp = this.handleKeyUp.bind(this);
}
handleKeyUp = (e) => {
this.props.onDenomChange(e.target.value, this.state.denom.name);
this.setState({ denom: /*new state identitcal to change in redux store*/ })
}
edit2: An example of raising state up. The steps are:
1. Connect one of your parent components and grab the appropriate slice of state with a mapStateToProps function.
2. Pass the props through your connected parent component to DenomInput.
4. In this.denomsChange, dispatch the appropriate action. It is unclear what this is since you did not include your action in the post.
class DenomInput extends Component {
...
render() {
return (
<div className="input-group denom">
<span className="input-group-addon">{this.props.denom.label}</span>
<input
type="text"
className="form-control"
onChange={this.handleKeyUp}
value={this.props.denom.sum} />
<span className="input-group-addon">{this.props.denom.count | 0}</span>
</div>
);
}
}
export default DenomInput;

Categories

Resources