My Loading component:
import React from 'react'
export default class Loading extends React.Component {
constructor(props) {
super(props)
this.state = {
display: 'none'
}
}
render() {
return (
<div className="loading" style={{display: this.state.display}}>
<span></span>
</div>
)
}
}
And I want change display from App.js
Loading.setState ...
Or
var lng = new Loading()
lng.setState ...
Both of them not work
I want can change state from another class or function
If you want to change display from App.js:
Pass it as prop to Loading component, and keep the state at App.js.
pass some prop from App.js and when it changes - change the state
of display in App.js
Use some global state/store manager like Redux or built-in useContext react-hook, in this case you will be able to change from any component connected to store
Solution sample
A simple solution can be found in a code sandbox example.
Related
I got an app that is working on react using a class component, i found a code of a feature that i would like to add to my code but it's made using a functional component. The code is here https://codesandbox.io/s/framer-motion-animate-in-view-gqcc8 but the relevant part is this.
import { useInView } from "react-intersection-observer";
import { motion, useAnimation } from "framer-motion";
import "./styles.css";
function Box() {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start("visible");
}
}, [controls, inView]);
I don't know how to add that controls variable in my class component
class App extends Component {
constructor(props) {
super(props);
this.state = {
curtains: null,
loading: true,
renderNav: false
};
}
Should i add it on my state? i don't understand how to make it works in class component
You can't use hooks inside of a class component. What you can do is to write a little wrapper that exposes the ref and controls in a render prop:
const Controls = ({children}) => {
const controls = useAnimation();
const [ref, inView] = useInView();
useEffect(() => {
if (inView) {
controls.start("visible");
}
}, [controls, inView]);
return children(ref, controls);
};
Then you can use it like this:
class App extends Component {
// ...
render() {
return (
<Controls>
{(ref, controls) => (
<motion.div ref={ref} animate={controls}>
{/* content */}
</motion.div>
)}
</Controls>
);
}
}
Lets say you have
const functionalComponent=()=>{
return <h1>Functional componenet</h1>
}
and you want to change it to class component
use this import at the top:
import React,{Component} from "react";
and change your code to something like this:
Class functionalComponent extends Component{
state={}
render(){
return <h1>functional component</h1>;
}
}
your functional component is now changed to class component.
And to use it in your existing class component , you don't need to change your functional component to class component unless you require local state.
with the introduction of react hooks that's also changed i.e, you don't have to change your functional component to class component if you plan to use hooks.
In your code : useEffect is a hook and you can't use it inside a class component.
I would recommend simply importing the functional component inside your class component and if you have to pass some value , you can pass it as a prop.
And as far as importing your functional component is concerned:
import React,{Component} from "react";
import Box from "./Box.js";
class App extends Component {
constructor(props) {
super(props);
this.state = {
curtains: null,
loading: true,
renderNav: false
};
render(){
return(<Box/>);
}
}
You can also use functional components anywhere like a class component. Btw is also using so no need to worry about the thing that you cannot use state in it.
Use:
<Box props={props}/>
I am not really sure how to properly ask this question but I will explain what I'm trying to do here:
So I have this parent Component which creates a Component like so:
<CurrentTemperature cityName={this.state.cityName}></CurrentTemperature>
The CurrentTemperature Component looks like this:
import React, { Component } from "react";
import "../App.css";
export default class CurrentTemperature extends Component {
constructor(props) {
super(props);
this.state = {
temperature: 0,
cityName: this.props.cityName,
};
}
componentDidMount() {
//fetch the temperature from api here
}
render() {
return (
<div>
<div className="city-temperature">
{this.state.cityName} {this.state.temperature}
</div>
</div>
);
}
}
All I'm trying to do is read the city name from the parent, then fetch the current temperature from my API, and then display both of those in the Component. But if I try to console.log(this.props.cityName) from anywhere other than from inside the city-temperature div, I always get an empty string. What is going on here?
cityName is the state of the parent component. I guess the parent component would get the "cityName" asynchronously. right? If this is the case, You have to put the temperature in the parent component as its state. And you have to insert the API call in the parent component. CurrentTemperature component will behave like a pure function component.
const CurrentTemperature = ({temperature, cityName}) => {
return (
<div className="city-temperature">
{cityName} {temperature}
</div>
);
}
I guess this is not only the solution but also the best DX.
You can remove this in your constructor, and then use this.state.cityName
constructor(props) {
super(props);
this.state = {
temperature: 0,
cityName: props.cityName,
};
}
I'm trying to render a new instance of an object but I'm not sure how to call the render function or how to set the state from outside the object itself.
//App.js
import React from 'react';
import './App.css';
import DrawMessage from './components/DrawMessage'
function App() {
var Draw = new DrawMessage();
Draw.setState({
test: 'THIS IS A NEW TEST!'
});
return (
<div className="App">
<header className="App-header">
<DrawMessage/>
<Draw/>
</header>
</div>
);
}
export default App;
//DrawMessage.js
import React from 'react'
class DrawMessage extends React.Component {
constructor (props){
super(props)
this.state = {
test: 'THIS IS A TEST!'
}
}
render () {
return <div className='message-box'>
Hello {this.state.test}
</div>
}
}
export default DrawMessage
using the DrawMessage in the return yields "Hello THIS IS A TEST!" which is the default response
But if I was able to render the Draw i was expecting to see "Hello THIS IS A NEW TEST!" as i want to change the state of "test"
I am assuming that I cant call the render function from Draw the way i did and I don't think I am properly changing the state of test.
Calling setState on a child from a parent is not conventional React. I'd remove all of the following, and instead just invoke DrawMessage in the return of App:
var Draw = new DrawMessage();
Draw.setState({
test: 'THIS IS A NEW TEST!'
});
One way to achieve your goal would be to set the state of DrawMessage in its constructor function, and then change it via componentDidUpdate() when the props passed from App change. If you're considering that route, ask yourself the following: does DrawMessage need to have its own state? If its state is often changed from the parent, it may be better served as part of props. React will re-render DrawMessage when props change.
componentDidUpdate() docs
Via JSX: var myTinyObject = <TinyObject prop1={prop1} prop2={prop2} />;
Via React.createElement: var myTinyObject = React.createElement(TinyObject, { prop1, prop2 }, null);
How to initialize state with dynamic key based on props? The props is a data fetched from external source (async). So the props will change when the data is succesfully downloaded. Consider a component like this.
edit: I want to make the state dynamic because I want to generate a dialog (pop up) based on the item that is clicked. the DialogContainer is basically that. visible prop will make that dialog visible, while onHide prop will hide that dialog. I use react-md library.
class SomeComponent extends React.Component {
constructor() {
super();
this.state = {};
// the key and value will be dynamically generated, with a loop on the props
// something like:
for (const item of this.props.data) {
this.state[`dialog-visible-${this.props.item.id}`] = false}
}
}
show(id) {
this.setState({ [`dialog-visible-${id}`]: true });
}
hide(id) {
this.setState({ [`dialog-visible-${id}`]: false });
}
render() {
return (
<div>
{this.props.data.map((item) => {
return (
<div>
<div key={item.id} onClick={this.show(item.id)}>
<h2> Show Dialog on item-{item.id}</h2>
</div>
<DialogContainer
visible={this.state[`dialog-visible-${item.id}`]}
onHide={this.hide(item.id)}
>
<div>
<h1> A Dialog that will pop up </h1>
</div>
</DialogContainer>
</div>
);
})}
</div>
)
}
}
// the data is fetched by other component.
class OtherComponent extends React.Component {
componentDidMount() {
// fetchData come from redux container (mapDispatchToProps)
this.props.fetchData('https://someUrlToFetchJSONData/')
}
}
The data then is shared via Redux.
However, based on my understanding so far, state can be updated based on props with componentWillReceiveProps or the new getDerivedStateFromProps (not on the constructor as above). But, how to do that on either method?
The example here only explains when the state is initialized on the constructor, and call setState on either cWRP or gDSFP. But, I want the key value pair to be initialized dynamically.
Any help/hint will be greatly appreciated. Please do tell if my question is not clear enough.
import React from 'react';
import {connect} from 'react-redux';
import {yourAction} from '../your/action/path';
class YourClass extends React.Component {
state = {};
constructor(props){
super(props);
}
componentDidMount(){
this.props.yourAction()
}
render() {
const {data} = this.props; //your data state from redux is supplied as props.
return (
<div>
{!data ? '' : data.map(item => (
<div>{item}</div>
))}
</div>
)
}
}
function mapStateToProps(state) {
return{
data:state.data //state.data if that is how it is referred to in the redux. Make sure you apply the correct path of state within redux
}
}
export default connect(mapStateToProps, {yourAction})(YourClass)
If you do this, <div>{item}</div> will change as you change the data state. The idea is to just map the redux state to your class props - you don't have to map the props back to the state. The render() automatically listens to changes in props supplied by redux. However, if you do want to somehow know redux state change in events, you can add the following functions.
componentWillReceiveProps(newProps){
console.log(newProps)
}
getDerivedStateFromProps(nextProps, prevState){
console.log(nextProps);
console.log(prevState);
}
Can I use an instance of a reactJS component to render a component.
Eg, Let's say my reactJS component is
class myComponent extends Component{
constructor(props){
super(props)
this.state = {
next:false
}
this.alertSomething = this.alertSomething.bind(this);
this.showNext = this.showNext.bind(this);
}
showNext(){
console.log('wow');
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
alertSomething(){
alert('Alert Something')
console.log(this.state, this, this.state.next);
this.setState({next:true});
}
render(){
return(
<div className='column'>
</div>
)
}
}
export default myComponent
Now, inside my another component can I do;
let x = new displayContent.renderComponent();
render(
<x />
//or
<x.render />
)
// I tried both it didn't work, I thought there mush be some other way to achieve this, after all every component is just a javascript object.
Also at the same time, can I call function to make change in its state. Like.
x.someFunction();
where someFunctino is inside that react component, doing setState.
Is it possible? OR am I missing something?
Edit: I clearly understand that when you want to render a react component, you can always do, <component />.
This question is just out of curiosity, can this be done? if not, then why?, I mean how is that different from other javascript objects.
Well, you can use the React.createElement method to render a component:
React.createElement(Component, params)
but with JSX, this is the same:
<Component />
Refer to Multiple components in the React documentation.
This is not how you're supposed to use React. You don't have to handle object instantiations ; React do this for you. Use composition instead.
render() {
return (
<myComponent />
)
}
Also, if you want to set the state of a child component from a parent component, you should probably move the logic in the parent.
Probably you are looking for something like this.
import React, { Component } from "react";
import CamCapture from './CamCapture.js';
export default class ProctorVideoFeed extends Component{
constructor(props) {
super(props);
this.Camera = React.createElement(CamCapture);
}
//this.handleVideoClick = this.handleVideoClick.bind(this);
render(){
return(
<div>
<span>{this.Camera}</span>
<button onClick = {this.Camera.StopRecording}>Stop</button>
</div>
)
}
}
Here StopRecording is a function defined inside CamCapture class.