React, how to load states/properties from child components - reactjs

Ok, let's say I have a component like:
Which is formed by 2 different components:
1) The entire rectangle(let's call it card)
2) Each side(the square) is another component(let's call it cardSide)
I added a button on card that when clicked it gathers all the information on each one of the cardSide components(text, note, image, etc).
My questions are, How can I achieve that?
I've read about passing refs from parent to children and sending props from parent to children, but I haven't found any example of the opposite getting the props/states from children components.
I have no much experience on React and I'm using hooks and functions instead of classes(in case that matters) in Java this is very easy to do this by accessing the get methods of each instance, how can be done in React?.

see this url: Call child method from parent. and read the ansewers of rossipedia.
it seems "Using Class Components (>= react#16.4)" section will be more useful for you.

You will need to create a function / method in the parent container that sets the state. From there you can pass it down to the child component which will be able to set the state of its parent.

In order to achieve this communication i suggest that the child (CardSide Component) communicates with the Card Component via Events .
so when the user finish his operation on the card component an event is fired passing all the data to the parent let me show you an example for what i mean :
Card Component
class Card extends Component {
handleCompelete = data => {
//the data here are all the data entered from the child component
//do some sorting using table name
};
render() {
return <CardSide onCompelete={this.handleCompelete} />;
}
}
CardSide Component
class CardComponent extends Component {
render() {
return (
<div>
{/* data here reprensets what you need to transfer to parent component */}
<button onClick={() => this.props.onCompelete(data)} />
</div>
);
}
}
Edit
You cannot access the state of the child component as it is private to it.
Regarding to the props , you can access it but it is ReadOnly that is passed from the parent component but the child component cannot modify it .
Actually there is a way to access the component children (but i see it will complicate your code rather than simplifying it and i do not recommend this )
lets say that this is you app.js
class App extends Component {
constructor() {
super();
this.state = {
name: "React"
};
}
render() {
return (
<div>
<h1>Title</h1>
<Card>
<CardSide someProp="My Child Prop Value" />
</Card>
</div>
);
}
}
as you can see i included CardSide with property with name someProp as a child for Card rathar than inserting it inside Card Component
In the Card Component i accessed the children property as the following :
class Card extends Component {
handleCompelete = data => {
//the data here are all the data entered from the child component
//do some sorting using table name
};
render() {
return <div>
{this.props.children}
{console.log(this.props.children)}
{this.props.children.props.someProp}
</div>;
}
}
and the CardSide Component
class CardSide extends Component {
render() {
return (
<div>
{/* data here reprensets what you need to transfer to parent component */}
<button onClick={() => this.props.onCompelete(data)} >
Hello btn
</button>
</div>
);
}
}
As you can see it will get your structure more complicated and it will be hard to know who is the children for the card component without intensive tracing .
you can see the code in action via this link https://stackblitz.com/edit/react-fxuufw?file=CardSide.jsx

Related

React. the order of the render method of nested components and how does it work with Redux

I'm working on a project that displays courses on a page. to get courses, I use redux to store the fetched courses. Below is the main course page:
Course.js:
class Course extends Component{
constructor(props){
super(props);
this.state = {
id: "",
}
}
render() {
return(
<CourseWrapper>
{/* <Fragment> */}
<div className={"test"}>
{console.log(store.getState()),
this.props.currentCourse.length < 1 ? null : this.props.currentCourse[0]["units"]}
</div>
<Dashboard />
<div>
{}
</div>
{/* </Fragment> */}
</CourseWrapper>
);
}
}
const mapStateToProps = state => {
return{
currentCourse: state.courses.currentCourse,
}
}
I emit 'getCourse()' action inside the constructor of CourseWrapper component.
CourseWrapper.js:
class CourseWrapper extends React.Component{
constructor(props){
super(props);
console.log("wrapper")
this.props.getCourseTest("noUse");
}
render(){
return(
<div>
{console.log(this.props.children),
this.props.children}
</div>
)
}
}
const mapDispatchToProps = dispatch =>{
return {
getCourseTest: noUse => dispatch(getCourse(noUse)),
}
}
export default connect(null,mapDispatchToProps)(CourseWrapper);
When I checked the console.log, I found that 1. the first log is the one under that shows the initial state of the store having no courses, then 2. "wrapper" inside CourseWrapper.js constructor, and next 3. children wrapped by , and finally 4. the 'store.getStore()' again under containing the expected course object.
My Questions are: why is the first log the initial state of the store instead of "wrapper"? and it doesn't have course obj inside. it leads to the next question that originally I think the constructor of CourseWrapper is called first, which dispatch 'getCourse' action, then its children get rendered. However, the logs showed that somehow {console.log(store.getState()) gets called first, doesn't CourseWrapper being rendered first? or I have some misunderstanding of how render actually arrange nested components
https://reactjs.org/docs/faq-state.html
Calls to setState are asynchronous - don’t rely on this.state to reflect the new value immediately ...
CourseWrapper used inside Course that means CourseWrapper constructed inside Course.render... and
render actually does not render anything it constructs a description of that what should be rendered by React some time later. You can say that JSX translates to something like
render() {
return(
create_node(CourseWrapper,
...
create_node(div,
...
console.log(store.getState()),
...
)
)
)
}
So, as you can see console.log(store.getState()) called inside Course.render, and then somewhere in create_node called a new CourseWrapper and then CourseWrapper.render, and only then console.log("wrapper")
(Don't think of it as an actual React algorithm, it's just and overly simplyfied principle)
Then following the same idea: <div>... OK, <div> is difficult to call a child of CourseWrapper... Let's say that CourseWrapper.render looks like this
render(){
return(
<div>
<SomeChild/>
{this.props.children}
</div>
)
}
then SomeChild is a child of CourseWrapper, and this.props.children - also its children, but while this.props.children have been already created inside Course before CourseWrapper, SomeChild was created inside CourseWrapper after it
No, before rendering, component should get its children, you can even find them in props.children in parent's constructor. So properties for children JSX objects should be calculated first.
console.log(store.getState()) will be calculated as it is inside of div JSX
CourseWrapper constructor calls and get div as children
render function of CourseWrapper invokes
If CourseWrapper rendering any other components - their constructors and render functions invoke

Reactjs coding with parent and child component

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.

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 interop

I'm new to react and am working through the tutorials. I think I have a grasp on the Multiple Components parent-child explanation, but am struggling to figure out how to provide interop (in state, events, etc) between independent components. So, given the following indepent, stateful components (that have child components, etc):
ReactDOM.render(
<FooBox />,
document.getElementById('foo')
);
and
ReactDOM.render(
<BarBox />,
document.getElementById('bar')
);
Is there a way to interop between FooBox and Barbox, or do I need to nest both under ReactDOM.render? And if I do, will that still "work"?
Use case: onClick of one of Foo's children, I want to display BarBox (with stateful information from FooBars children.
Yes, you should render into a single element so that you have a "single entry point" for the application and its corresponding React DOM. Some parent component can then control whether BarBox is displayed by setting a boolean on its local state.
For example, you could pass an onClick handler via props to FooBox:
class Parent extends React.Component {
displayBarBox () {
this.setState({ displayBarBox: true })
}
render () {
return (
<div>
<FooBox onClick={this.displayBarBox.bind(this)} />
{this.state.displayBarBox &&
<BarBox />}
</div>
)
}
}
And then use this click handler in FooBox:
class FooBox extends React.Component {
render () {
// Use the click handler passed via props
// (simple example)
return <div onClick={this.props.onClick} />
}
}
FooBox.propTypes = {
onClick: PropTypes.func.isRequired
}

Resources