I have three components.
export default class PermissionHandler extends React.Component {
constructor(props) {
super(props);
this.state = {
permission: true
}
}
}
export default class App extends React.Component {
render() {
return(
<PermissionHandler />
<Component1 />
)
}
}
export default class Component1 extends React.Component {
render() {
return(
<SomeComponent /* visible= true/false depends on permission */ />
)
}
}
I want PermissionHandler state to be used by any other components directly without using events or local state. Is it possible?
Can I use refs to achieve this goal?
export default class App extends React.Component {
constructor(props) {
super(props);
this.permissionHandler = React.createRef();
}
render() {
return(
<PermissionHandler ref={this.permissionHandler} />
<Component1 permissionHandler={this.permissionHandler}/>
<Component2 permissionHandler={this.permissionHandler} />
)
}
}
export default class Component1 extends React.Component {
render() {
return(
<SomeComponent visible={this.props.permissionHandler.currenct.state.permission} />
)
}
}
But Component1 doesnt rerender when the state of PermissionHandler updates
Simply move your state up the tree, to the App component
Related
import React from 'react';
import Multiselect from 'react-bootstrap-multiselect';
class Test2 extends React.Component {
constructor(props){
super(props)
this.state = {
list: [{value:'One',selected:true},{value:'Two'},{value:'Three'},{value:'Four',label:'Four Label'}]
}
}
render(){
return (
<Multiselect data={this.state.list} multiple />
);
}
}
export default Test2;
Here i am using react-bootstrap-multiselect
The ui is not coming properly.
Am i missing something?
PLease have a look.
try removing label attribute,
import React from 'react';
import Multiselect from 'react-bootstrap-multiselect';
class Test2 extends React.Component {
constructor(props){
super(props)
this.state = {
list: [{value:'One',selected:true},{value:'Two'},{value:'Three'},{value:'Four'}]
}
}
render(){
return (
<Multiselect data={this.state.list} multiple />
);
}
}
export default Test2;
I'm trying to use React Context API to pass props, however I got "undefined" error. The version of react is 16.3.2, and react-dom version is 16.3.2. The following is my code:
Provider.jsx:
import React from 'react';
export const PathContext = React.createContext({
rootPath: "http://localhost/example"
});
App.jsx:
import React from 'react';
import {PathContext} from './Provider.jsx';
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div>
<PathContext.Provider>
<AppRootPath />
</PathContext.Provider>
</div>
)
}
}
class AppRootPath extends React.Component {
render() {
return(
<div>
<span>App Root Path</span><br />
<PathContext.Consumer>
{
({rootPath}) => <span>{rootPath}</span>
}
</PathContext.Consumer>
</div>
)
}
}
export default App;
I can't find any problems in here, but the console reports this error: TypeError: Cannot read property 'rootPath' of undefined, and the error happens in here: ({rootPath}) => <span>{rootPath}</span>
About using a default value:
If there is no Provider for this context above, the value argument
will be equal to the defaultValue that was passed to createContext().
But you are wrapping it with Provider. Try removing Provider:
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return(
<div>
<AppRootPath />
</div>
)
}
}
class AppRootPath extends React.Component {
render() {
return(
<div>
<span>App Root Path</span><br />
<PathContext.Consumer>
{
({rootPath}) => <span>{rootPath}</span>
}
</PathContext.Consumer>
</div>
)
}
}
I don`t know where i do wrong.I cant send data from child to parent.
What is wrong here?
How can i grab the state from child and send to parent state?
this is the child component
import React from 'react';
export class Child extends React.Component{
constructor(props) {
super(props);
this.state= {
counter2: 5
}
}
render() {
return(
<div>
<button onClick={this.props.data}>Click me</button><span>{this.state.counter2}</span>
</div>
);
}
}
export default Child;
and i want to update the state in parent component
import React from 'react';
import {Child} from './Child';
export default class Parent extends React.Component{
constructor(props){
super(props);
this.state= {
counter: 0
}
}
update(){
this.setState({
counter: this.props.state.counter2
});
}
render(){
return(
<div>
<span>{this.state.counter}</span>
<Child data={this.update.bind(this)}/>
</div>
);
}
}
but i have a error:
×
TypeError: Cannot read property 'counter' of undefined?
i cant understand what i do wrong!
Thank you
Actually, you don't have state property in your Parent's props.
You can't get child's state in a such way:
this.props.state.counter2
Props ONLY passed from parent component to child (if you don't use Redux or another state management library).
Nevertheless, you can pass it like this:
Parent component
import React from 'react';
import {Child} from './Child';
export default class Parent extends React.Component{
constructor(props){
super(props);
this.state= {
counter: 0
}
}
update(value){
return () => {
this.setState({
counter: value
});
}
}
render(){
return(
<div>
<span>{this.state.counter}</span>
<Child data={this.update.bind(this)}/>
</div>
);
}
}
Child component
import React from 'react';
export class Child extends React.Component{
constructor(props) {
super(props);
this.state= {
counter2: 5
}
}
render() {
return(
<div>
<button onClick={this.props.data(this.state.counter2)}>Click me</button><span>{this.state.counter2}</span>
</div>
);
}
}
export default Child;
You are not passing content2 state in the child component correctly
You need to pass it with the button
<button onClick={()=> this.props.data(this.state.counter2)}>Click me</button><span>{this.state.counter2}</span>
Then in your update function
update = (data) =>{
this.setState({
counter: data
});
}
Note: no need to bind update function if you are using arrow function
like me.
<div>
<span>{this.state.counter}</span>
<Child data={this.update)}/>
</div>
Can I use children in React Container or is it wrong?
For example, I have a list of buttons(ActionButton) that are grouped together (ActionMenu).
import React from 'react';
class App extends React.Component {
render() {
return (
<ActionMenu>
<ActionButton name="New" icon="add" />
<ActionButton name="Delete" icon="remove" />
</ActionMenu>
)
}
}
class ActionMenu extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
alert('Click!');
}
render() {
return React.Children.map(this.props.children, (button) =>
React.cloneElement(button, {
onClick: this.handleClick
})
);
}
}
function ActionButton({ name, icon, onClick }) {
return <button class={icon} onClick={onClick}>{name}</button>
}
You can use children regardless of whether it's a component of container.
"[children are] especially common for components like Sidebar or Dialog that represent generic 'boxes'."
In your case you have a menu, which falls into this category.
https://reactjs.org/docs/composition-vs-inheritance.html
I think this is what you are after. Actually you should just put the children in its closest parent instead of its grandpa.
import React from 'react';
import { render } from 'react-dom';
function ActionButton({ name, handleClick }) {
return <button onClick={handleClick}>{name}</button>
}
class ActionMenu extends React.Component {
constructor(props) {
super(props);
}
handleClick = () => {
alert('Click!');
}
render() {
return (
<div>
<ActionButton name="add" handleClick={this.handleClick}/>
<ActionButton name="remove" handleClick={this.handleClick} />
</div>
);
}
}
class App extends React.Component {
render() {
return (
<ActionMenu />
)
}
}
render(<App />, document.getElementById('root'));
You can try to run it in sandbox.
By the way, using bind is quite redundant now, we can use public class fields syntax, which is already ECMA stage 2.
I want to change the state of the component A from an onClick handler of a button that is located in the component B, I currently have my code like this:
Component A:
import React, { Component } from 'react'
import ComponentB from './component_b'
class ComponentA extends Component{
constructor(props){
super(props);
this.state=({
allergies11:'',
allergies12:'',
allergies13:'',
allergies14:''
})
this.onCCDSubmit = this.onCCDSubmit.bind(this);
}
onCCDSubmit(e){
e.preventDefault()
this.setState({
allergies11:'Penicillin',
allergies12:'2/13/10',
allergies13:'Hives',
allergies14:'moderate'
})
this.on
}
render(){
return(
<div>{this.state.allergies11} {this.state.allergies12} {this.state.allergies13} {this.state.allergies14}
<ComponentB />
<div>
)
}
}
export default ComponentA;
Component B:
import React, { Component } from 'react';
class ComponentB extends Component{
render(){
return(
<button type="button" onClick={this.onCCDSubmit}>Import</button>
)
}
}
export default ComponentB;
how can i achieved this, any help is welcome!
You can pass a callback to your Component B, which would trigger the callback upon click...
Component B:
import React, { Component } from 'react';
class ComponentB extends Component{
render(){
return(
<button type="button" onClick={this.props.clickHandler}>Import</button>
)
}
}
export default ComponentB;
Component A:
import React, { Component } from 'react'
import ComponentB from './component_b'
class ComponentA extends Component{
constructor() {
super();
this.handleClickB = this.handleClickB.bind(this);
}
handleClickB(e) {
e.stopPropagation();
this.setState({
// new state you want to set...
});
}
render(){
return(
<div>{this.state.allergies11} {this.state.allergies12} {this.state.allergies13} {this.state.allergies14}
<ComponentB clickHandler={this.handleClickB} />
<div>
)
}
}
export default ComponentA;