React.createRef(); always null - reactjs

I tried looking at other posts but, can't seem to find a solution. Here is my code:
export default class DrumPad extends React.Component {
constructor(props) {
super(props);
this.audio = React.createRef();
this.testRef = React.createRef();
console.log(this.testRef.current);
}
render() {
return (
<div
ref={this.testRef}
className="drum-pad"
id={this.props.id}
>
<h1>{this.props.keyTrigger}</h1>
<audio
ref={this.audio}
src={this.props.sourceUrl}
className="clip"
id={this.props.keyTrigger}
></audio>
</div>
);
}
}
I'm doing the Drum Machine Project in freeCodeCamp. I'm currently stuck here. I'm trying to trigger the audio with a click, and from my research it seems that I need to use ref to make this work. But I'm stuck. I keep getting null when I console.log() the ref.current.

Related

Class state not found

Problem: I am trying to console.log() my component state, but seem to get a undefined property.
Code:
class App extends Component{
constructor(props) {
super(props);
this.state = {switch: false};
}
handleClick(){
console.log(this.state.switch)
}
render(){
return (
<div className="App">
<button onClick={this.handleClick}> ON </button>
</div>
)
}
}
Can someone please explain to me why I am getting an error
The context of the handleClick function is not that of the class when it is called. You can prove this by running console.log(this) inside the function.
To fix this, you can bind the function:
Add this line to the end of your constructor:
this.handleClick = this.handleClick.bind(this);
Source:
https://codeburst.io/binding-functions-in-react-b168d2d006cb

Ref keeps returning null

I looked at lots of ref examples, not one is working. Can someone tell me why this ref keeps returning null?
class GeneralNav extends Component {
constructor(props) {
super(props);
this.showMenuTitle = React.createRef();
console.log(this.showMenuTitle.current)
}
render() {
return (
<div>
<p ref={this.showMenuTitle}>menu</p>
</div>
);
}
}

Child not updating after Parent State changed

I am quite new with React and I have problem bellow
I have a parent component like this:
class Parent extends React.Component {
constructor(props) {
super(props);
this.state = {count:1};
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
return false;
}
setCount = () => {
this.setState({
count: 2
});
};
render() {
const {name, running, onRun, onStop} = this.props;
return (
<div>
<Test count={this.state.count}/>
<p><a href="#" onClick={this.setCount}>SetCount</a></p>
</div>
);
}
}
And here is Test component
class Test extends React.Component {
constructor(props) {
super(props);
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
return true;
}
render() {
const {count} = this.props;
return (
<div>
{console.log("Counting")}
<p>{count}</p>
</div>
);
}
}
I have method "shouldComponentUpdate" returns "false" in Parent component because I don't want to re-render it.
My understanding is React know which part of DOM need to be re-rendered. And in this case, the state of Parent changes will re-render "Test" component
But when I run above code, "Test" component does not redender.
Is there anything wrong in my code?
Thanks a lot for your help
You need to return true from your parent's shouldComponentUpdate method.
If you return false, after the initial render it won't update, even if you call a function that calls setState.
Is the refresh of the whole page are you talking about? If thats the case, probably you wanna change your <a> tag to button or use e.preventDefault();.
If not, I am not sure if that is possible. If you setState in the parent, it will rerender parent as well as the children. If you dont want to render the parent then you have to manage individual state management in the child level.
For example,
class Parent extends React.Component {
constructor(props) {
super(props);
}
render() {
const {name, running, onRun, onStop} = this.props;
return (
<div>
<Test/>
</div>
);
}
}
class Test extends React.Component {
constructor(props) {
super(props);
this.state = {count:1};
}
setCount = (e) => {
e.preventDefault();
this.setState({
count: 2
});
};
render() {
const {count} = this.state;
return (
<div>
{console.log("Counting")}
<p>{count}</p>
<p><a href="#" onClick={this.setCount}>SetCount</a></p>
</div>
);
}
}

Should I make all class variables part of state?

Say I have a class variable which I know won't change but is still needed to render the component. Something like this perhaps:
class MyComponent extends React.Component {
constructor(props) {
super(props);
let { arrayOfImages } = this.props;
this.arrayOfImages = arrayOfImages;
this.state = {
colorOfBackground: 'blue'
};
}
render() {
let images = this.arrayOfImages.map(image => {
return <img src={image.src} />
});
return (
<div style={{color: this.state.colorOfBackground}}>
{images}
</div>
);
}
}
Is it better to just make the arrayOfImages part of the state or just keep it as a class variable?
No, It is not necessary to put arrayOfImages in state if this will not change. It is better to put those value in state which can be change and want to re-execute code every time or conditionally when it change.

Pass data through levels - open Modal dialog at the end

I've been pounding my head on this for many hours and could use some help.
Fundamentally, what I am trying to do is that I have two layers of components - the last of which is supposed to open up a Modal Dialog when you click it. Because of React's idea that a component should only change its own state, I want to propagate that data up and set that variable.
Here is the layout. The FirstLevel.jsx file is the top of my hierarchy. It is followed by SecondLevel.jsx and ThirdLevel.jsx which is where the actual text is clicked.
I don't know about the syntax on anything. Not sure if onUserInput is the right attribute to use or handleUserClick is a built-in thing or a user-defined thing. The idea here is that I am trying to propagate the callback function handleUserClick down into the SecondLevel. Is this right so far?
FirstLevel.jsx
export default class FirstLevel extends React.Component {
constructor(props) {
super(props);
this.state = {
dialogActive: ''
};
this.handleUserClick = this.handleUserClick.bind(this);
}
handleUserClick(dialogActive) {
this.setState({
dialogActive: dialogActive
});
}
render() {
<SecondLevel onUserInput={this.handleUserClick}/>
}
Now, on the SecondLevel, I propagate the callback function even further down into the ThirdLevel. Is this the right way to do it so far?
SecondLevel.jsx
render () {
//other logic and tags before this
<ThirdLevel onUserInput={this.props.onUserInput}/>
}
Now this level is where all hell breaks loose and I have no idea what I am doing. On the click, I want to set the dialogActive variable that was propagated down and then let that float back up. I still don't know if onUserInput is the right thing to do or if the parameter is even correct. Everything is very hazy because it was just gotten by following tutorials and doing lots of Googling and throwing in bits and pieces from everywhere.
ThirdLevel.jsx
export default class ThirdLevel extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onUserInput(
this.dialogActive.value
);
//show Modal dialog somehow
}
render() {
return <text ref={(input) => this.dialogActive = true} onClick={this.handleClick}> {this.props.value}</text>;
}
Finally, I want to show some modal dialog. Clicking the text needs to reveal a modal dialog. The modal dialog is in another component called MyModal.jsx
In the ThirdLevel, I've tried importing MyModal and tried calling the showModal function. Didn't work. Then, I tried doing some React.createElement(MyModal) stuff and rendering it but that didn't work. All kind of other things that I forgot and just trying stuff until it works but it didn't. What am I doing wrong?
MyModal.jsx
export default class MyModal extends React.Component {
constructor(props) {
super(props);
this.state = {show: false};
this.showModal = this.showModal.bind(this);
this.hideModal = this.hideModal.bind(this);
}
showModal() {
this.setState({show: true});
}
hideModal() {
this.setState({show: false});
}
render() {
return (
<Modal
{...this.props}
show={this.state.show}
onHide={this.hideModal}
dialogClassName={styles.largeDialogBox}
>
//more modal stuff here
);
}
}
Big picture: trying to propagate a click action back up to the top of the hierarchy to set some state and that click action needs to open a modal dialog. Any help would be greatly appreciated.
Edit
Do I do something like this in my ThirdLevel?
handleClick() {
this.props.onUserInput(
this.dialogActive.value
);
//show Modal dialog somehow
var newmodal = new MyModal(this.props);
React.render(React.createElement(newModal));
}
render() {
return <text onClick={this.handleClick}> {this.props.value}</text>;
}
Edit 2
My ThirdLevel render function returns this:
<div>
<MyModal isDialogActive={this.props.dialogActive} onHideModal={this.props.onUserInput}/>
<tspan onClick={this.handleClick}> {this.props.value} </tspan>
</div>
When that gets passed back up into the SecondLevel, it becomes:
<text>
<div>
<MyModal isDialogActive={this.props.dialogActive} onHideModal={this.props.onUserInput}/>
<tspan onClick={this.handleClick}> {this.props.value} </tspan>
</div>
</text>
It's weird to wrap things in the div but that's the only way to make the render work. Even though the resulting DOM has all the tags there, none of the actual tspans are showing.
I believe this will get you on the right path.
I would suggest refactoring the name of some of your functions as it does get a bit confusing. handleUserClick then onUserInput etc. But you've already mentioned that in your OP.
// First Level
export default class FirstLevel extends React.Component {
constructor(props) {
super(props);
this.state = {
dialogActive: false
};
this.handleUserClick = this.handleUserClick.bind(this);
}
handleUserClick(dialogActive) {
this.setState({
dialogActive: dialogActive
});
}
render() {
<SecondLevel onUserInput={this.handleUserClick}/>
}
}
// Second Level
...
render () {
//other logic and tags before this
<ThirdLevel onUserInput={this.props.onUserInput}/>
}
...
// Third Level
export default class ThirdLevel extends React.Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.props.onUserInput(true);
}
render() {
return (
<div>
<MyModal isDialogActive={this.props.dialogActive} onHideModal={this.props.onUserInput} />
<button onClick={this.handleClick}>Show Modal</button>
</div>
)
}
}
// Modal
export default class MyModal extends React.Component {
constructor(props) {
super(props);
this.hideModal = this.hideModal.bind(this);
}
hideModal() {
this.props.onUserInput(false);
}
render() {
return (
<Modal
{...this.props}
show={this.props.isDialogActive}
onHide={this.hideModal}
dialogClassName={styles.largeDialogBox}
>
//more modal stuff here
);
}
}
However I would be asking why you need this logic in the FirstLevel and it cannot be further down the component tree.

Resources