Can I use refs in render? - reactjs

The following code obviously doesn't work
But the Idea is, I would like to conditional rendering depending on a child component's clientHeight, not sure if it's possible
class App extends Component {
constructor() {
super();
this.comp = {};
this.state = {
clientHeight: 0
};
}
componentDidMount() {
console.log(this.comp)
this.setState({
clientHeight: this.comp.clientHeight
});
}
render() {
return (
<div>
<Hello name={this.state.name} ref={comp => this.comp = comp}/>
{
this.state.clientHeight > 100 ? <ComponentA /> : <ComponentB />
}
</div>
);
}
}

you could do this by setting clientHeight value from <Hello/> component
class App extends Component {
constructor() {
super();
this.state = {
clientHeight: 0
};
}
handler(newSize) {
this.setState({
clientHeight: newSize
})
}
render() {
return (
<div>
<Hello name={this.state.name} onResize={this.handler}/>
{
this.state.clientHeight > 100 ? <ComponentA /> : <ComponentB />
}
</div>
);
}
}
you can get window height by window.addEventListener('resize', ((c)=>{console.log(window.innerHeight)}));

It turn out #Dane's idea helped me. with componentDidUpdate hook. this achiever what I want, but it renders twice every time, one for the ref to be assigned, and change update to the new clientHeight, then render again base on the new clientHeight. Not sure if there is a better way.
class App extends Component {
constructor() {
super();
this.comp = {};
this.state = {
clientHeight: 0
};
}
componentDidUpdate(prevProps){
if(prevProps !== this.props){
this.setState({
clientHeight: this.comp.clientHeight
})
}
}
render() {
return (
<div>
<Hello name={this.state.name} ref={comp => this.comp = comp}/>
{
this.state.clientHeight > 100 ? <ComponentA /> : <ComponentB />
}
</div>
);
}
}

Related

Change CSS by passing data between siblings

I have two child components. The first child is an image and the second child is a search input. When I type something in the input field, I want the image to hide itself. The passing of data from the second child to the parent goes well. But the first child still appears...
Parent:
class Main extends React.Component {
constructor() {
super();
this.state = {
displayValue: 'block'
};
}
hideImage = () => () => {
alert('You pressed a key, now the apple should be gone')
this.setState ({
displayValue: 'none'
});
};
render() {
return (
<div>
<Image />
<Search hideImage={this.hideImage()}/>
</div>
);
}
}
ReactDOM.render(<Main />, document.getElementById('root'));
First Child:
export default class Image extends Component {
render() {
return (
<div>
<img style={{display : this.props.displayValue}} src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTAxoq2YSBjoS0Lo3-zfqghoyNzZ9jHxoOc5xuFBoopMtKP6n4B"></img>
</div>
)
}
}
Second Child:
export default class Search extends Component {
render() {
return (
<div>
<input onInput={this.props.hideImage} placeholder="Search someting"></input>
</div>
)
}
}
You have to pass the displayValue state into your Image component as a prop. Also you have to pass the hideImage function without initializing it using the two brackets. The below code should work for you.
class Main extends React.Component {
constructor() {
super();
this.state = {
displayValue: 'block'
};
}
hideImage = () => () => {
alert('You pressed a key, now the apple should be gone')
this.setState ({
displayValue: 'none'
});
};
render() {
return (
<div>
<Image displayValue={this.state.displayValue}/>
<Search hideImage={this.hideImage}/>
</div>
);
}
}
You just had a couple of typos.
class Image extends React.Component {
render() {
return (
<div>
<img
style={{ display: this.props.displayValue }}
src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTAxoq2YSBjoS0Lo3-zfqghoyNzZ9jHxoOc5xuFBoopMtKP6n4B"
alt="altprop"
/>
</div>
);
}
}
// Second Child:
class Search extends React.Component {
render() {
return (
<div>
<input onInput={this.props.hideImage} placeholder="Search someting" />
</div>
);
}
}
class Main extends React.Component {
constructor() {
super();
this.state = {
displayValue: "block"
};
}
hideImage(e) {
e.preventDefault();
alert("You pressed a key, now the apple should be gone");
this.setState({
displayValue: "none"
});
};
render() {
return (
<div>
<Image displayValue={this.state.displayValue}/>
<Search hideImage={this.hideImage.bind(this)} />
</div>
);
}
}
Call your Image component like this
<Image displayValue={this.state.displayValue} />
It should then already work, but here is a shorter way to write your code.
// First Child:
const Image = ({displayValue}) => <div>
<img alt='' style={{display : displayValue}} src="https://encrypted-tbn0.gstatic.com/images?q=tbn%3AANd9GcTAxoq2YSBjoS0Lo3-zfqghoyNzZ9jHxoOc5xuFBoopMtKP6n4B"></img>
</div>

React passing props to child and back to parent

My current structure is like this:
state={
activetab=1,
activetab2=2}
<child1 activetab={activetab}/>
<child2 activetab2={activetab2}/>
And I would like when the user changes the active tab from child 2 to update the state on the parent component, and then also handle the change on the child1 component.
child 1 code :
render() {
const activetab=this.props;
this.showimage1 = () => {
if (activetab === 1) {
return (
<img src={slide1} alt='' />
)
} else null;
}
return (
<div>
{this.showimage1()}
</div>
child 2 code :
constructor (props) {
super(props)
this.changetab= this.changetab.bind(this)
this.state={
activetab:1}
}
render () {
const activetab2=this.props;
changetab(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
})
}
}
return(
<div>
<button onClick={() => {
this.changetab(1)
}}
>tab1 </button>
</div>
So as you can see I want when the user changes the current tab from child 2 to pass the props in my parent component so that the child1 component knows which image to show depending on the tab. Anyone knows how to do it without rewriting everything in a single component?
Create a main component that renders the two component child 1 and 2 create only 1 source of truth means only 1 state to be pass to the child components as props.
export class MainComponent extends Component {
constructor (props) {
super(props)
this.changetab = this.changetab.bind(this)
this.state={
activetab: 0
}
}
changetab(tab) {
if (this.state.activeTab !== tab) {
this.setState({
activeTab: tab
})
}
render() {
return (
<div>
<ChildOne activetab={this.state.activetab} />
<ChildTwo activetab={this.state.activetab} changetab={this.changetab} />
</div>
)
}
}
// ChildOne Component pass state activetab as props
render() {
const { activetab } = this.props;
this.showimage1 = () => {
if (activetab === 1) {
return (
<img src={slide1} alt='' />
)
} else null;
}
return (
<div>
{this.showimage1()}
</div>
// ChildTwo Component
render () {
const { activetab, changetab } = this.props;
return(
<div>
<button onClick={() => {
this.changetab(1)
}}
>tab1 </button>
</div>
The parent component must have 2 function handlechange that you pass to your childs.
Will look something like that
// Parent
class Parent extends React.Component {
// Constructor
constructor(props) {
this.state = {
child1: 1,
child2: 0
};
}
handleChangeChild1(state) {
this.setState({ child1: state });
}
handleChangeChild2(state) {
this.setState({ child2: state });
}
render() {
return (
<div>
<Child1 onXChange={this.handleChangeChild1} />
<Child2 onYChange={this.handleChangeChild2} />
</div>
);
}
}
And in the children you do
class Child extends React.Component {
constructor(props) {
super(props)
}
handleChange(e) = () => {
this.props.onXChange
}
render() {
return (
<input onChange={this.handleChange} />
)
}
}
I recommend you read the doc
You can wrap the components in a parent component. Then you can pass a function from the parent to child 2 by attaching it to a prop. Child 2 can then call this function on a change.
In the parent:
render() {
const someFunction = (someVariable) => {
// do something
}
return(
<child2 somePropName={ this.someFunction } />
)
}
edit: removed .bind() from this example

passing state of child component

So I have a component "itemSelection" and inside of it I map through an api response like this
<div className="row">
{this.state.items.map(i => <Item name={i.name} quantity={i.quantity} />)}
</div>
Here the state of "Item" component
constructor(props){
super(props);
this.state = {
visible: false,
selected: false,
}
}
How could I pass the state of "Item" component to "itemSelection" component?
Sending data back up to your parent component should be done by using props.
Fairly common question, see this post for the long answer.
As according to me, If I understood your question you want to call the state of the child component to the parent component.
//Child.js
import s from './Child.css';
class Child extends Component {
getAlert() {
alert('clicked');
}
render() {
return (
<h1 ref="hello">Hello</h1>
);
}
}
export default withStyles(s)(Child);
//Parent.js
class Parent extends Component {
render() {
onClick() {
this.refs.child.getAlert()
}
return (
<div>
<Child ref="child" />
<button onClick={this.onClick.bind(this)}>Click</button>
</div>
);
}
}
Also, you can get the code reference from the link: https://github.com/kriasoft/react-starter-kit/issues/909
This a little tricky but Maybe, its help you solving your problem.
//Parent.js
class Parent extends Component {
component(props) {
super(props)
this.state = {
test: 'abc'
}
}
ParentFunction = (value) => {
this.state.test = value;
this.setState(this.state);
}
render() {
return (
<div>
<Child
test={this.state.test}
ParentFunction={this.ParentFunction}
/>
</div>
);
}
}
//Child.js
import s from './Child.css';
class Child extends Component {
component(props) {
super(props)
this.state = {
test: props.test
}
}
handleChange = () => {
this.state.test = event.target.value;
this.setState(this.state);
this.handleOnSave()
}
handleOnSave = () => {
this.props.ParentFunction(this.state.test);
}
render() {
return (
<div>
<input type="text" onChange={this.handleChange} />
</div>
);
}
}
export default withStyles(s)(Child);

Send a prop to a child component

I am trying to change one component of a child component when another child component makes some action.
I have a parent class here:
class Parent extends Component {
constructor(){
super();
this.state={visible:true};
}
handleClick = () => {
this.setState({ visible: !this.state.visible });
};
render() {
return (
<div>
<Child1 handleClick={this.handleClick} />
<Child2 visible={this.state.visible} />
</div>
);
}
}
class Child1 extends Component {
handleClick = () => {
console.log(this.props);
this.props.handleClick();
};
render() {
return (
<div>
<button onClick={this.handleClick}>Click</button>
</div>
);
}
}
class Child2 extends Component {
render() {
return <div>//some codes</div>;
}
}
The function handleClick from the parent function works once.
Then it keeps giving me the error saying _this.props.handleClick is not a function. And there are no props from the second time.
Can anyone tell me what am I doing wrong?
I did this and it works :
render() {
return (
<div>
<Child1 handleClick={this.handleClick} />
{ this.state.visible && <Child2 />}
</div>
);
}
For reference : https://codesandbox.io/s/5zl8q7l744
Hope it helps.

React js - I can't remove a component

I have this code:
class ItemWrap extends Component {
constructor() {
super();
this.state = { showItem: true};
this.removeItem = this.removeItem.bind(this);
}
removeItem() {
this.setState({ showItem: false });
}
render() {
var item = this.state.showItem ? <Item data_items={this.props.data_items} /> : '';
return (
<div id="sss">
{item}
<button onClick={this.removeItem}>remove image</button>
</div>
);
}
}
export default ItemWrap;
On button click I remove {item}. But the button is stay. I need to remove all ItemWrap after button click.
Help me )
Firstly,removeItem function is designed for change flag of state,
and then you can use this flag to veiw whatever you want.
ex:
if(flag)
return (your current div);
else
return(
whatever you want , empty or other
)
The rendering should be managed in the parent component, here is a possible solution
class ItemWrap extends Component {
constructor() {
super();
}
render() {
return (
<div id="sss">
<Item data_items={this.props.data_items} />
<button onClick={this.props.onClickBtn}>remove image</button>
</div>
);
}
}
export default ItemWrap;
then in the wrapper you can manage the rendering of ItemWrap
class Wrapper extends Component {
constructor() {
super();
this.state = { showItem: true};
this.removeItem= this.removeItem.bind(this);
}
removeItem() {
this.setState({ showItem: false });
}
render() {
return (
<div>
{ this.state.showItem && <ItemWrapper onClickBtn={this.removeItem} /> }
</div>
);
}
}
export default Wrapper;

Resources