React | Having trouble enacting state changes in child component - javascript

I am coding a checkers web app and have set up user interaction by placing onclick functions on the components. I have two different components pieces and spaces. Ideally, the onclick functions are linked to methods in the parent component which interpret the state of the component being clicked and responds by returning data back to the component or a separate component. The issue is, I do not understand how to send data to child components from the parent following the mounting of said child component. I understand you can use props to initialize the state in a child component, but is there anyway I can update the child component from the parent following this initialization? I am new to react so I'm not exactly sure how inter component communication works quite yet.

You can pass update function to child, I hope this helps.
Parent
import React, { Component } from 'react'
export default class Parent extends Component {
constructor(props) {
super(props);
this.state={
something:""
}
}
updateSomething = (anotherThing) => {
this.setState({something:anotherThing})
}
render() {
return (
<div>
{/* we are passing updateSomething function in props*/}
<ChildComponent updateSomething={(anotherThing)=>this.updateSomething(anotherThing)}/>
</div>
)
}
}
Child
import React, { Component } from 'react'
export default class ChildComponent extends Component {
render() {
return (
<div>
{/* we are using updateSomething function to update parents state*/}
<button onClick={()=>this.props.updateSomething("anotherThing")}>Update Parents state</button>
</div>
)
}
}

Related

Add react component to html element

I have a containerElement and a react component. I want to add the react component into the containerElement. Is there a way I can do it? I have tried containerElement .appendChild(), but not working.
const containerElement = document.getElementById(divId);
React component: <ReactComponent></ReactComponnet>
ReactDOM.render(<ReactComponent/>, document.getElementById(divId));
Following the React lifecycles, you shouldn't have to insert the component into your parent component (containerElement). The react component should be inserted in the normal flow as a child or grandchild of the parent component.
If I'm understanding your question correctly, you need to handle the case where you are getting the DOMElement outside the normal flow of the React lifecycle. For that you can use refs.
For example below, define the component you're trying to insert somewhere in the render lifecycle of your container. No matter how nested the child is, you can "get" the child DOM element just like you are trying to do with document.getElementById from your question.
class Parent extends React.Component {
constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return (
<FunctionComponent ref={this.myRef} />
);
}
}
Hope this helps

How to access isValid variable from one.js to two.js in ReactJS?

I am facing issue in below problem
Below is the code stored in 'one.js'
const One= (props) => {
const [isValid, setIsValid]=useState(true);
return(
<div>Hello</div>
);
}
export default One;
Below is the code stored in 'two.js'
import One from './one.js';
var Two=()=>{
return(
<div>Two</div>
);
}
export default Two;
You can't access state of One component, because state is private to each component and this inaccessible
But you can create common parent component and use callback functions to change it's state and pass value to Two component as prop
Flow - One -> CallbackFunction -> Parent -> Props -> Two
Also you can try to use useContext and share some data values between Two and One
you can't access component's state from another component in reactjs
you have to learn and use redux for this goal or use hooks
but if you want to do it in pure reactjs you have to make one component parent of another component and send the state as props to child component
like this:
//one.jsx
class one extend React.Component{
constructor(props){
super(props)
this.state = {
text: ""
}
}
render(){
return <Two props={this.state.text} />
}
and then use this in two.jsx component
class Two extend React.Component{
render(){
<div>{this.props.text}</div>
}
}

Getting a changed variable to show up in `render`

Probably a simple question with a simple answer, but I can't figure this out. Blame the heat. My simulator prints 'this is a test' on the screen, when I want it to say 'changed'. What am I doing wrong?
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Template from './src/components/Template';
export default class App extends React.Component {
constructor(props) {
super(props);
this.foo= "this is a test";
}
changeMe = () => {
this.foo = 'changed';
}
componentDidMount(){
this.changeMe();
}
render() {
return (
<Template foo={this.foo} />
);
}
}
Use state
You are using a class attribute witch will not trigger a re-render when changed. In react a component will re-render when it receives new props or when the state is changed (there's also a way to force it but best not to do that).
Example using the state to trigger a rerender
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import Template from './src/components/Template';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state ={foo: "this is a test"};
}
changeMe = () => {
this.setState({foo:'changed'})
}
componentDidMount(){
this.changeMe();
}
render() {
return (
<Template foo={this.state.foo} />
);
}
}
When passing new props to a component it will also re-render (unless you implement componentShouldUpdate).
State explanation
So inside a react component you have a local state object in this.state it can be set in the constructor like this.state = {bar: 'foo'};. After the constructor has set the state it should only be changed with the this.setState() method.
Upon changing the state with setState the component will re-render with the updated values.
The state is not available outside of the component, at least not available as this.state because that would call the local state of the current component.
If you need to use a value from the state of a parent component you can pass it to a child. At that point it becomes a prop of the child accessible with
this.props
To change the value of state from a child component you should pass a function to the child that changes the state of the parent.
This process of passing state changing functions becomes increasingly complex as your app grows, I would suggest using a library like Redux to manage app state via actions and reducers. There is a steep learning curve but once you have a grasp of this modified flux methodology you will wonder how you ever lived without it.

How can a parent alter props for a child component in react?

I'm new to react, and am a little confused about something. I've read many articles online claiming that a component cannot alter its own props, but that a parent can alter the props of its children. However, I have seen nothing that actually shows how to do this.
I would like to be able to do this:
class Parent extends Component {
constructor(props) {
super(props);
this.childProps = {name:'name',age:12,type:'child'};
this.changeChild = this.changeChild.bind(this);
}
changeChildName(newName) {
//change prop 'name' of child here;
}
render() {
return (
<Child {...this.childProps} />
);
}
}
However, I can't figure out how to do this at all - despite almost all the material that I've read on React saying that a parent can change its child's props. What I can get to work properly is as follows:
class Parent extends Component {
constructor(props) {
super(props);
this.state = {name:'name',age:12,type:'child'};
this.changeChild = this.changeChild.bind(this);
}
changeChildName(newName) {
this.setState({name: newName});
}
render() {
return (
<Child {...this.state} />
);
}
}
It seems a bit overkill to me that the Parent needs to re-render when the only thing that I want to re-render is the child view. How can I change the props of the <Child> component from the <Parent> component?
Secondary Questions
1) Is it possible to change the state of a component without having the component re-render?
2) Is there an onStateChange type event that we can tap into, or do we solely have componentWillReceiveProps?
1) Is it possible to change the state of a component without having the component re-render?
No, and it makes very little sense.
2) Is there an onStateChange type event that we can tap into, or do we solely have componentWillReceiveProps?
There is no, use componentWillReceiveProps.
It seems a bit overkill to me that the Parent needs to re-render when the only thing that I want to re-render is the child view.
Actually this is where you trick yourself: the parent IS changed, since what it returns is changed. The whole tree is being re-rendered from the root.
I think you misunderstand. It is very simple for a parent to change the child props... Just change the props that get rendered. Now, what if we want to do some changes in child without rerendering the parent. This is also pretty simple.
Attach a ref to your child and work with it. Now, the child cannot change its own props, so anything you mess with within the child will not be a prop. Props are passed down from the parent every time the parent rerenders.
So,
class Parent extends Component {
constructor(props) {
super(props);
this.childProps = {name:'name',age:12,type:'child'};
}
doSomethingOnChild() {
this.refs.child.callFunctionOfChildThatWillMessWithItself();
}
render() {
return (
<Child {...this.childProps} ref="child" />
);
}
}

ReactJS: Mutating child state from parent via props

Disclaimer: I have looked at Reactjs: how to modify child state or props from parent? and do not believe the answer fits my question.
So I have a reusable, stateful conversation component that renders different DOM based on its state. I also have to be able to control which DOM is rendered from the parent.
TL;DR - How should I mutate a child components state from the parent, if at all, what other options are there?
The Child:
export default class Conversation extends Component {
constructor(props) {
super(props);
this.state = {
newConversation: props.showNewConversation
};
}
render() {
if (!this.state.newConversation) {
return (
<div>Current Conversation</div>
);
} return (
<div>New Conversation</div>
);
}
}
Now I need to render this component in various places, but I need to render the appropriate DOM depending on the parent, i.e. from the navbar you can create a new conversation, and from the users page you can go directly to your conversation with them, so I can control when I call the child via it's prop.
Calling child and setting state via prop:
<Conversation
showNewConversation={this.state.isConversationShown === true}
/>
This is currently working, but I've been told this is a very bad practice in React, my question is actually why this is considered bad practice, and what a good practice solution would look like.
In React, the general best practice is to make as many components 'state-less' if possible. Usually, state isn't necessary if you aren't loading async data or are accepting user input.
In this example the main issue happens as follows: If the parent renders
<Conversation newConversation={true} />
And later on rerenders it to
<Conversation newConversation={false} />
Then the child will not render as expected as React will 'update' the child conversation (re-render) but will not call the constructor again. Because you only transferred the props to the state in the constructor, the child will never change.
Rather most components should render only as a function of their properties. Your child can be adapted to the following:
export default class Conversation extends Component {
constructor(props) {
super(props);
}
render() {
if (!this.props.newConversation) {
return (
<div>Current Conversation</div>
);
} return (
<div>New Conversation</div>
);
}
}
Here, an update by the parent will allow the child to correctly re-render because you directly reference the props in the render() function of the child.
If you had more data about the conversation being rendered, then you should pass in all the data as a prop. i.e.
<Conversation conversationData={{name: 'abc', new: false}} />
Then the Conversation component can access the props directly in the render() method.
If you absolutely must change the state, then it should be in the form of a change in props by the parent:
export default class Conversation extends Component {
constructor(props) {
super(props);
this.state = {
newConversation: props.showNewConversation
};
}
// Response to change
componentWillReceiveProps(nextProps){
this.setState({newConversation: this.props.showNewConversation});
}
render() {
if (!this.state.newConversation) {
return (
<div>Current Conversation</div>
);
} return (
<div>New Conversation</div>
);
}
}

Categories

Resources