Following is the UI, in which each box I am trying to display after 1 sec delay - (Box1, 1 sec delay, Box2, 1 sec delay, Box3 ..so on)
Instead I am getting -
My React code and let me know what I am doing wrong here & why its showing numbers -
const CreateBox = (props) => {
return (
<>
{/*<div className="box">{props.num}</div>*/}
<div className="box"></div>
</>
)
}
const App = () => {
return (
<div className="app">
<h3>App</h3>
{
[1,2,3,4,5,6,7,8,9,10].map((item) => {
return setTimeout(() => {
// return (<CreateBox num={item} />)
return (<CreateBox />)
}, 1000)
})
}
</div>
)
}
const root = document.querySelector('#root')
ReactDOM.render(<App />, root)
Codepen - https://codepen.io/anon/pen/pBLPMY
Instead of creating a new timeout for every element in the array on every render, you could create an interval in componentDidMount and increment a number in your state until it reaches 10 and use this number in your render method instead.
Example
class App extends React.Component {
state = {
count: 0
};
componentDidMount() {
const interval = setInterval(() => {
this.setState(
({ count }) => ({ count: count + 1 }),
() => {
if (this.state.count === 10) {
clearInterval(interval);
}
}
);
}, 1000);
}
render() {
return (
<div className="app">
<h3>App</h3>
{Array.from({ length: this.state.count }, (_, index) => (
<CreateBox key={index} num={index + 1} />
))}
</div>
);
}
}
const CreateBox = props => {
return <div className="box">{props.num}</div>;
};
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Don't use setTimeout while looping. Instead set the timer inside the CreateBox component using state. If you remove the timeout you can see the boxes. To handle the delay pass the index * 1000 as a timer for each element.
class CreateBox extends React.Component {
state = {
opacity: 0
}
constructor(props){
super(props)
}
componentDidMount(){
setTimeout(()=> this.setState({opacity: 1}),`${this.props.time}000`)
}
render() {
console.log(this.props)
return (
<div style={this.state} className="box">{this.props.num}</div>
)
}
};
const App = () => {
return (
<div className="app">
<h3>App</h3>
{
[1,2,3,'w',5,6,7,8,9,10].map((item, index) => <CreateBox num={item} time={index}/>)
}
</div>
)
}
const root = document.querySelector('#root')
ReactDOM.render(<App />, root)
const CreateBox = (props) => {
return (
<div className="box">{props.num}</div>
)
}
const App = () => {
return (
<div className="app">
<h3>App</h3>
{
[1,2,3,4,5,6,7,8,9,10].map((item) => {
return (<CreateBox num={item} />)
})
}
</div>
)
}
const root = document.querySelector('#root')
ReactDOM.render(<App />, root)
Related
I am fairly new to React. I have currently made a loading screen in React with useEffect, but I'm not sure how to make it with class Components. This is my functional component which works.
const [sourceLoading, setSourceLoading] = React.useState(true);
// control when to stop loading
useEffect(() => {
setTimeout(() => {
setSourceLoading(false);
}, 1000);
}, [])
return (
<div>
{sourceLoading ? (<LoadingScreen />): (
<>
</>
)}
</div>
);
I'm currently converting the function like so, however it isn't working, and my loading screen never appears. Where am I going wrong? is componentDidMount not the correct substitution for useEffect here?
this.state = {
sourceLoading: true,
};
this.componentDidMount = this.componentDidMount.bind(this);
componentDidMount() {
setTimeout(() => {
this.setState({ sourceLoading: false});
}, 1000);
}
render() {
return (
<div>
{this.sourceLoading ? (<LoadingScreen />) : (<>
</>
)}
</div>
);
}
It works for me, if you change this line:
{this.sourceLoading ? (content) : ""}
// should be
{this.state.sourceLoading ? (content) : ""}
class App extends React.Component {
constructor() {
super();
this.state = {
sourceLoading: true,
};
}
componentDidMount() {
setTimeout(() => {
this.setState({
sourceLoading: false
});
}, 1000);
}
render() {
return (
<div>
{this.state.sourceLoading ? "loading" : "not"}
</div>
);
}
}
ReactDOM.render( <App /> , document.getElementById("root"));
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
You need to access the state in render function like
{this.state.sourceLoading ? (<LoadingScreen />) : null}
I want to update icon of component from another component. whenever I clicked on a playlist music start playing and icon should be change to pause instead of play but I don't know how I can update the state of a component from another component.
PlayList Component -
playlist and musics are in this component
class PlayList extends React.Component {
render() {
const playMusic = () => {
musics.forEach(e => e.pause());
musics[this.props.arr].play();
musics[this.props.arr].currentTime = 0;
nowPlaying = this.props.arr;
clickedOnMusic = 'clicked';
};
return (
<div>
<Card>
<CardActionArea onClick={playMusic} />
</Card>
</div>
)
}
BottomAppBar Component -
icons and some function to playing music are here
class BottomAppBar extends React.Component {
state = {
displayPlay: 'none',
displayPause: '',
displayVolume: '',
displayMute: 'none'
};
render(){
return(
<IconButton onClick={handleChangePlay} style={{ color: 'white' }}>
<PauseCircleOutlineRoundedIcon
style={{ fontSize: 46, display: this.state.displayPlay }}
/>
<PlayCircleOutlineIcon
style={{ fontSize: 46, display: this.state.displayPause }}
/>
)
}
thank you very much for reading !
Wrap them in a container and maintain their states over there.
Ex:
<Parent>
<PlayList/>
<BottomAppBar />
</Parent>
You can use the context api, any ascendent of PlayerLogic can access whatever you put in the context with React.useContext and will be re rendered when values in the Context change.
const PlayerContext = React.createContext();
const PlayerLogic = ({ children }) => {
const [state, setState] = React.useState({
playing: false,
});
const setPlaying = React.useCallback(
val =>
setState(current => ({ ...current, playing: val })),
[]
);
const pause = React.useCallback(() => setPlaying(false), [
setPlaying,
]);
const play = React.useCallback(() => setPlaying(true), [
setPlaying,
]);
return (
<PlayerContext.Provider
value={{
state,
pause,
play,
}}
>
{children}
</PlayerContext.Provider>
);
};
const ComponentOne = () => {
const {
pause,
play,
state: { playing },
} = React.useContext(PlayerContext);
return (
<div>
{playing ? (
<button onClick={pause}>pause</button>
) : (
<button onClick={play}>play</button>
)}
</div>
);
};
class ComponentTwo extends React.Component {
render() {
return this.context.state.playing
? 'now playing'
: 'nothig is playing';
}
}
ComponentTwo.contextType = PlayerContext;
const A = () => <B />;
const B = () => <C />;
const C = () => {
const {
state: { playing },
} = React.useContext(PlayerContext);
return `In component C, is playing ${JSON.stringify(
playing
)}`;
};
const App = () => (
<PlayerLogic>
<ComponentOne />
<ComponentTwo />
<div>
<A />
</div>
</PlayerLogic>
);
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>
I'm new in React. I'm developing a screen but I have a issue, I don't know how insert the children in the parent if the state condition is equals, I'm using an array to print the parent and children but depends of the data the parent could have a children or not, for example if (parent.rework_name === children.rework_name) ? print the children : 'nothing in the parent'.
Please let me know if you have an idea how to solve this, many many thanks in advance.
This is the goal, my code works but the damn children is outside the parent :(
class Filling extends Component {
constructor() {
super();
this.state = {
fillingStations: [],
};
}
componentDidMount() {
getDataAPI('http://localhost:8080/api/parent')
.then((station) => {
getDataAPI('http://localhost:8080/api/children')
.then((data) => {
const stationArray = [];
station.map((item, index) => {
stationArray.push(
<ReworkStation key={index} title={index + 1} status='' />,
);
data.map((it, idx) => {
const f2Date = it.f2_time.substr(0, 10);
const f2Hour = it.f2_time.substr(11, 8);
const f2DateFormatted = `${f2Date.substr(8, 2)}/${f2Date.substr(5, 2)}/${f2Date.substr(0, 4)}`;
const color = selection_color(it.color_d);
return (
stationArray.push(item.rework_name === it.rework_name && <ReworkTitle key={idx} vin={it.vin} date={f2DateFormatted} ipsq={it.defects} hour={f2Hour} color={color} />)
);
});
});
console.log(stationArray);
this.setState({
fillingStations: stationArray,
});
});
});
}
render() {
return (
<div className='row'>
{ this.state.fillingStations }
</div>
);
}
}
I don't know how to insert the children inside the parent already render.
I already solved, first render all the parent divs and after replace the position array with array.splice
render() {
const array = [];
this.state.fillingStations.map((item, index) => (
array.push(<Parent key={index} title={index + 1} status='' />),
this.state.fillingChildren.map((it, ind) => {
if (item.name === it.name) {
parent.splice(index, 1,
<Parent {...this.props}}>
<Child {...this.props} />
</Parent >);
}
})
));
return (
<div className='row'>
{array}
</div>
);
}
}
I want to make a counter app with increment, decrement and add counter button. But add counter function is not working. It's showing this error:
Parsing error: Adjacent JSX elements must be wrapped in an enclosing tag. Did you want a JSX fragment <>...?
i have already tried enclosing it in tags,still its not working.
import React,{Component} from 'react';
import './App.css';
export class App extends Component {
state={
count:0,
}
increment=()=>{
this.setState({ count: this.state.count + 1 });
}
decrement=()=>{
this.setState({ count: this.state.count - 1 });
}
addCounter=()=>{
<span><button onClick={this.increment}>+</button></span>
<span>{this.state.count}</span>
<span><button onClick={this.decrement}>-</button></span>
}
render() {
return (
<div className="App">
<button onClick={this.addCounter}>Add Counter</button>
</div>
)
}
}
export default App;
add counter function should add another counter just below the previous counter.
Basically extract a Counter component.
Then have your App maintain a list of Counter components.
// Counter Component
export class Counter extends React.Component {
state = {
count:0,
}
increment=()=>{
this.setState({ count: this.state.count + 1 });
}
decrement=()=>{
this.setState({ count: this.state.count - 1 });
}
render() {
return (
<div>
<span><button onClick={this.increment}>+</button></span>
<span>{this.state.count}</span>
<span><button onClick={this.decrement}>-</button></span>
</div>
);
}
}
// App Component
export class App extends React.Component {
state = {
counters: [], // additional state for Counter components
}
addCounter = () => {
this.setState({
counters: [
...this.state.counters,
Counter
]
})
}
render() {
return (
<div className="App">
<button onClick={this.addCounter}>Add Counter</button>
{ this.state.counters.map((Counter, index) => (
<Counter key={index} />)
)}
</div>
)
}
}
Demo
You are just adding more spans and button but refering to the same counter.
state={
i : 0,
count:0,
}
var newCount="counter"+this.state.i;
this.setState({
i : this.state.i+1,
})
this.setState({
count: {
...this.state.count,
newCount: 0
}
});
So with this you add a new counter with a progresive autoincrement number.
I think it is what you want to do.
const { useState } = React;
function App(){
const [counter, setCounter] = useState([]);
function addCounter(){
setCounter(counter.concat({id: counter.length, count: 0}));
}
function increase(id){
setCounter(counter.map(el=>{
if(el.id === id){
el.count++;
}
return el;
}));
}
function decrease(id){
setCounter(counter.map(el=>{
if(el.id === id){
el.count--;
}
return el;
}));
}
return (
<div className="App">
<button onClick={addCounter}>Add Counter</button>
{
counter.map(el=>{
return(
<div key={el.id}>
<span>Counter #{el.id}</span>
<div>
<button onClick={()=>{increase(el.id)}}>+</button>
<span>{el.count}</span>
<button onClick={()=>{decrease(el.id)}}>-</button>
</div>
</div>
)
})
}
</div>
)
}
ReactDOM.render(
<App />, document.getElementById('root')
)
<script crossorigin src="https://unpkg.com/react#16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#16/umd/react-dom.development.js"></script>
<div id="root"></div>
Your "counter" needs to be a react component with its own state, what you have there will have each "counter" you add use the same component state from App. You also do not save the returned JSX to then render anywhere.
const Counter = () => {
const [count, setCount] = useState(0);
return (
<div> // <-- React components can return only a single node*
<span>
<button onClick={() => setCount(count + 1)}>+</button>
</span>
<span>{count}</span>
<span>
<button onClick={() => setCount(count - 1)}>-</button>
</span>
</div>
);
};
class App extends Component {
state = {
counters: []
};
addCounter = () => {
this.setState(prevState => ({
counters: [...prevState.counters, <Counter />]
}));
};
render() {
return (
<div>
<button onClick={this.addCounter}>Add Counter</button>
{this.state.counters}
</div>
);
}
}
* React render lifecycle function can render arrays.
You have to add another functional Component instead of adding JSX. DEMO
import React from 'react';
const counter = (props) => {
return (
<div>
<span><button onClick={() => props.increment(props.index)}>+</button></span>
<span>{props.count}</span>
<span><button onClick={() => props.decrement(props.index)}>-</button></span>
</div>
)
}
export default counter;
And your main App component
import React, {Component} from 'react';
import Counter from './Counter';
import './App.css';
export class App extends Component {
state={
counters: []
}
valueChanger = (index, inc) => {
this.setState((prevState) => {
const counters = prevState.counters.slice();
counters[index] += inc;
return {
counters: counters
}
});
}
increment=(index)=>{
this.valueChanger(index, 1);
}
decrement=(index)=>{
this.valueChanger(index, -1);
}
addCounter=()=>{
this.setState((prevState) => {
return { counters: [...prevState.counters, 0] }
});
}
render() {
let counterElems = this.state.counters.map((c, index) => {
return <Counter key={index} index={index} increment={this.increment} decrement={this.decrement} count={c} />
});
return (
<div className="App">
{counterElems}
<button onClick={this.addCounter}>Add Counter</button>
</div>
)
}
}
export default App;
I have a react class component, where I am passing list of module names and some other attributes. I tried to obtain module code by calling a function getModuleCode() and passing module name as a parameter.
class ModulesListing extends React.Component {
getModuleCode(module){
var moduleCode = 0;
// Do relevant calls and get moduleCode
return moduleCode;
}
render(){
var {modulesList} = this.props;
modulesList.forEach(module => {
//here I need to call getModuleCode as getModuleCode(module.name)
var moduleCode = getModuleCode(module.name)
console.log(moduleCode)
})
return (
//Info to display
);
}
}
If I tried as above mentioned, it prints as undefined
Also tried with setting as state, which is not suitable for looping. Here what I wanted is to get module code wrt certain module.
You could get the codes in componentDidMount and in componentDidUpdate if the modulesList change, and store them in state.
Example
function doCall() {
return new Promise(resolve =>
setTimeout(() => resolve(Math.random().toString()), 1000)
);
}
class ModulesListing extends React.Component {
state = { codes: [] };
componentDidMount() {
this.getModuleCodes();
}
componentDidUpdate(prevProps) {
if (this.props.modulesList !== prevProps.modulesList) {
this.setState({ codes: [] }, this.getModuleCodes);
}
}
getModuleCodes = () => {
Promise.all(this.props.modulesList.map(doCall)).then(codes => {
this.setState({ codes });
});
};
render() {
const { modulesList } = this.props;
const { codes } = this.state;
if (codes.length === 0) {
return null;
}
return (
<div>
{modulesList.map((module, index) => (
<div>
{module}: {codes[index]}
</div>
))}
</div>
);
}
}
ReactDOM.render(
<ModulesListing modulesList={["a", "b", "c"]} />,
document.getElementById("root")
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>