Reactjs coding with parent and child component - reactjs

I have 3 components, that is 2 child components and one parent component.
I wanted to pass the child component value to parent (only the values not the components enitirely,it should not visible in parent) and this values from parent to another child component.
Any suggestions or logic of how to proceed on this, since I don't have any guidance as of right now I had to ask here. Is the above problem possible.
The code is very complex, so I have not put here.
Thank you

When you say values, do you mean state, props, user input, something else?
If you mean state or props: React has a 1-way data flow, so the easiest way to accomplish this is to actually store the data at a higher level. Either store the data used by the child in the parent and pass it down to the children for consumption, or else use a store that both parent and children have access to. Either way, this will make it much easier for all components to access the data.
If you mean user input: one way you can accomplish this is to pass a callback from the parent component to the child as a prop, and then in the child call that callback when a user does something or changes some value. The callback function can make the data accessible to the parent on that user action, and then you can decide what to do with the data from there.

AksharaDL,
Child to Parent — Use a callback and states
Parent to Child — Use Prop
Also here is another article explaining it: https://medium.com/#ruthmpardee/passing-data-between-react-components-103ad82ebd17

here is the solution.
in parrent component you have a state. and have a setData method to update state. pass setData to ChildOne use props. and data to ChilTwo and use it
class StoreBanner extends React.Component {
constructor() {
this.state = {
data: 'whatever'
}
}
setData = (data) => {
this.setState({data})
}
render() {
return (
<div>
<ChildOne setData={this.setData}/>
<ChildTwo data={this.state.data}/>
</div>
)
}
}
and in ChildOne you can update the parrent state
class ChildOne extends React.Component {
setParentData = () => {
this.props.setData('another')
}
...
}

You can do it like this.
class ParentComp extends React.Component {
constructor() {
super();
this.state = {
theStateToPass: null
}
this.receiveDataFromChild = this.receiveDataFromChild.bind(this);
}
receiveDataFromChild(data) {
this.setState({
theStateToPass: data
})
}
render() {
return (
<div>
<FirstChild updateMe={this.receiveDataFromChild} />
<SecondChild stateFromFirstChild={this.state.theStateToPass} />
</div>
)
}
}
class FirstChild extends React.Component {
constructor(props) {
super(props);
this.callParentMethod = this.callParentMethod.bind(this);
}
callParentMethod(e) {
let someDataToSend = "ABC";
this.props.updateMe(someDataToSend)
}
render() {
return (
<div onClick={this.callParentMethod}>
</div>
)
}
}
class SecondChild extends React.Component {
render() {
return (
<div>
{this.props.stateFromFirstChild}
</div>
)
}
}
however it becomes complex and might lead to one's pulling their hair out. so i would suggest using redux , it keeps the flow simple , you have a reducer , actions and a container. everything goes with a flow and keeps it clean but it does comes with an extra overhead of more code as you will be creating container reducer and actions.

Related

ReactJS createRef for N components, all point to the final one in the list

I have 3 components, App, Parent and Child. The App uses a method provided by Parent and registers the children into Parent. This is for the Parent to collect the Refs (create a dependency map) of the Children it encompasses.
Child has a method named Animate which will be invoked by Parent via refs created.
When I try to print the dependencyMap I can see an array is being generated, the way I expect.
But when I try to access the child components from Parent using the dependencyMap, it always invokes the last on on the list of children.
That is to say, when I try to animate < CustomComponent > using animateDependentChildren within Parent.js, the CustomComponent2 only gets animated, even if I pass the correctId for CustomComponent1.
App.js
export default class App extends React.Component {
render(){
return(
<Parent>
{
(props)=>{
return(
<View>
<CustomComponent1 ref={props.register('s1')} key={1}>Text</CustomComponent1>
<CustomComponent2 ref={props.register('s2')} key={2}>Text2</CustomComponent2>
<ListComponent id={'s1'} key={3}/>
<ListComponent id={'s2'} key={3}/>
</View>
)
}
}
</Parent>
);
}
}
Parent.js
class Parent extends React.Component{
constructor(props) {
super(props);
this.dependencyMap = {}
}
render() {
return (
<View>
{this.props.children({
register: this.register.bind(this)
})}
</View>
);
}
register(dependentOn){
let dependentRef = React.createRef();
if(!this.dependencyMap[dependentOn]){
this.dependencyMap[dependentOn] = [];
}
this.dependencyMap[dependentOn].push(dependentRef);
return dependentRef;
}
animateDependentChildren(listId){
let subscribers = this.dependencyMap[listId];
subscribers.forEach(subscriber => {
console.log('subscriber', subscriber);
console.log('subscriber dom', subscriber.current);
this.refs[subscriber].animate(scrollObj); // <-This function always animates the last of the list of children (ie CustomComponent2)
});
}
}
Any idea what Im doing wrong here? Cant React.createRef be used to create multiple references and then invoke them later individually?
As subscriber is the component ref, try changing this line:
this.refs[subscriber].animate(scrollObj);
...to:
subscriber.animate(scrollObj);
I hope this helps.

React+redux get data from child component

I have creator, I mean step1 -next-> step2 -next-> ...
In my parent component I have buttons preview and next, steps content are render as child.
class MyCreator extends React.Component {
render() {
return (
<div>
{this.renderStep(this.props.step.id)}
</div>
<div>
<button>back</button>
<button>next</button>
</div>
);
}
}
In a step I have a component which has only two methods: getData, setData. This is a third party component (so I cannot change implementation).
When I click button next I want to getData from the current step. I mean call some generic method on each step child component, like leaveStep. Then leaveStep returns some data, which I will pass to redux action.
If I got it right, the ideal solution would be lifting state up to the Parent component, take a look at this part of the React documentation. But since you don't have control of your components and it may create you some problems to sync the states. Something like this will do the trick:
class Parent extends Component {
state = {
childData: null
}
getChildData = (data) => {
this.setState({
childData: data,
}, () => { console.log(this.state); });
}
render() {
return <Child setData={this.getChildData} />
}
}
class Child extends Component {
state = {
data: 'this is child data'
}
render() {
return <button onClick={() => this.props.setData(this.state.data)}>Next</button>;
}
}
But remember that this creates a duplicate state, breaking the single source of truth and can be very messy for large applications.

Lifting up state in React

say i have this React Class. This is NOT my main component that I'm rendering. how can i pass the state i set in here UPWARDS to the parent component.
class Player extends React.Component {
constructor(props) {
super(props);
this.state = {
playerOneName: ''
}
this.selectPlayerOne = this.selectPlayerOne.bind(this);
}
selectPlayerOne(e, data) {
this.setState({playerOneName: data.value})
}
render() {
let players = [];
this.props.players.map((player) => {
players.push({text: player.name, value: player.name})
})
return (
<div className="playersContainer">
<div className="players">
<Dropdown onChange={this.selectPlayerOne} placeholder='Select Player One' fluid selection options={players} />
</div>
</div>
)
}
}
when I say parent component i mean the class that is going to display player like so:
<Player />
I.e. how can I make this.state.playerOneName available to the parent?
Hey so the point here is that you are basically passing in, from your parent component into your child component, a prop which is a function.
In parent:
handler(newValue){
this.setState({key: newValue})
}
render() {
return(
<Child propName={handler.bind(this)}>
)
}
When a change takes place in your child component, you call the function and pass in the new value as an input. This way you are calling the function in your child component, and making a change to the state of the parent component.
In your case you want to, instead of setting the state of playerOneName, pass in a function from the parent of this class and do something like this.props.functionFromParent(playerOneName) in your 'selectPlayOne' function.
It is true that the flux pattern is unidirectional, however when you're dealing with smart and dumb components you will see that data is passed from a dumb component to a smart component in this way. It is perfectly acceptable React form!
"Lifting state up" for React means that you should replace data from your child component to parent component state and pass data for presentation to child component by props.
You can do something like this to achieve your goal. Create a parent component which hold playerOneName as its state. Pass it as a prop to child component and with that also a function that changes the playerOneName whenever it is changed in the child component.
class Parent extends Component {
constructor(props){
this.state = {
playerOneName: ''
}
}
render() {
return(
<Child
playerOneName={this.state.playerOneName}
onPlayerOneNameChange={(playerOneName) => this.setState({playerOneName})}
/>
);
}
}
Use this function like this in child component to change the name of playerOneName in Parent component, like this your child component is only displaying the value of the playerOneName all the changes are done in Parent component only.
class Child = props => {
const { playerOneName, onPlayerOneNameChange } = props;
return (
<TextInput
value={playerOneName}
onChangeText={(playerOneName) => onPlayerOneNameChange(playerOneName)}
/>
);
}
By this you can use updated playerOneName in your Parent component whenever you like by using this.state.playerOneName

react component - parent child interaction; component Lifecycle

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} />;
}
}

React: Add child element after parent component has mounted

I have a parent component with child elements. I tried to add a child element after the parent component mounted:
class Parent extends React.Component {
componentDidMount() {
this.props.children.push(<NewChildComponent/>)
}
render() {
return (
<div>
{this.props.children}
</div>
)
}
}
Can someone tell me
1. How to add a child element after a parent has mounted
2. Why the above did not work
It's not working because you are mutating the props array manually - React has no idea that it has changed. In general, you should never change props at all.
If you really want to do this, you can use setState within componentDidMount, and then render your child component through that:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {
childComponent: null
}
}
componentDidMount() {
this.setState({ childComponent: <div>Hello</div> });
}
render() {
return (
<div>
{this.state.childComponent}
</div>
)
}
}
However, there might be a better solution to whatever you're trying to do. I can't imagine many situations in which you'd want to render stuff only after the parent has mounted.
Can you please try componentWillMount, I guess this will fix the problem

Resources