I'm working on todo app in React and I have weird problem. I created onClick effect on trash icon to remove whole task component. The thing is, sometimes it works (removes whole task), sometimes not (removes only icon). I tried different solutions but to be honest I have no idea why it works like this, this is the same script working differently in different components, for some reason.
main component:
import React from 'react'
import TaskContainer from './TaskContainer.js';
import SingleTask from './SingleTask'
class AppContainer extends React.Component {
constructor(props) {
super(props)
this.state = {
children: [],
numChildren: 0,
newMessage: "What to do next?"
}
this.onAddChild = this.onAddChild.bind(this)
this.handleChange = this.handleChange.bind(this)
}
onAddChild = (msg) => {
let newArray = this.state.children.concat(<SingleTask message={msg} />);
this.setState({ children: newArray });
console.log(this.state.children)
}
handleChange(event) {
this.setState({ newMessage: event.target.value })
}
render() {
return (
<div className="app-container">
<div className="new-task-container">
<input type="text" id="taskInput" defaultValue="What to do next?"
maxlength="50" onChange={this.handleChange} />
<div className="addTask" id="addTask" onClick={
() => {
let text = document.getElementById("taskInput").value;
this.setState({ newMessage: text })
this.onAddChild(this.state.newMessage);
}
}>
<div className="add-button">Add task</div>
</div>
</div>
<TaskContainer>
{this.state.children}
</TaskContainer>
</div>
)
}
}
export default AppContainer
child component
import SingleTask from './SingleTask.js';
function TaskContainer(props) {
return (
<div className="task-container">
{props.children}
</div>
)
}
export default TaskContainer
child's child component - SingleTask
import React from 'react'
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome'
import { faTrashAlt } from '#fortawesome/free-regular-svg-icons'
class SingleTask extends React.Component {
constructor(props) {
super(props)
this.state = { active: true }
}
render() {
return (
<div className="singleTask" >
<p>{this.props.message}</p>
<div className="removeTask" onClick={(event) => {
setTimeout(() => {
event.target.parentNode.parentNode.remove()
}, 350)
}
}>
<FontAwesomeIcon icon={faTrashAlt} />
</div>
</div>
)
}
}
export default SingleTask
thanks in advance
I create a CodeSandbox with all the necessary corrections.
https://codesandbox.io/s/upbeat-jang-v7jvm
Piece of advice: When using React is not recommend that you modify the DOM by yourself.
Related
I'm working on simple form element using react-js.
There are three component:
App
TakeInput
Index
problem is when user put text in input field setState() function not work properly and data not updated. For testing purpose when i'm placing console.log in app js component it shows undefined on console. anyone sort this please. I want to console the updated data when state update
App.js
import React, { Component } from 'react';
import InputField from './TakeInput';
class App extends Component {
state = {
userInp : '',
outText : ''
}
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}))
console.log(this.userInp);
}
render() {
return (
<div className="App">
<InputField changingVal={this.handlechanger2}/>
</div>
);
}
}
export default App;
TakeInput.JS
import React, { Component } from 'react';
class TakeInput extends Component{
state={
txt: ''
}
handlerChange = (e)=>{
const { changingVal } = this.props;
const v = document.getElementById("userInput").value;
changingVal(v);
// console.log(e.target.value);
this.setState({ txt: e.target.value })
}
render(){
return(
<input type="text" name="userInput" id="userInput" placeholder="Please Enter Text" onChange={this.handlerChange} value={this.txt}/>
)
}
}
export default TakeInput;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
it is about you are developing wrong way. I think you text input should be at your parent component
To read from state you should use this.state.abc
import React, { Component } from 'react';
class TakeInput extends Component{
handlerChange = (e)=>{
this.props.onChange(e.target.value);
}
render(){
return(
<input type="text" name="userInput" placeholder="Please Enter Text" onChange={this.handlerChange} value={this.props.txt}/>
)
}
}
export default TakeInput;
import React, { Component } from 'react';
import InputField from './TakeInput';
class App extends Component {
state = {
userInp : '',
outText : ''
}
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}))
console.log(this.state.userInp);
}
render() {
return (
<div className="App">
<InputField txt={this.state.userInp} onChange={this.handlechanger2}/>
</div>
);
}
}
export default App;
You're trying to console.log this.userInp. It should be this.state.userInp.
Also to see the update right after the last set state, you can do the following:
handlechanger2 = (v) => {
this.setState( () => ({
userInp: v,
}), function(){ console.log(this.state.userInp);}) // set a callback on the setState
}
I am using react-dom#16.6.1 and react#16.6.1 that should support react Context and trying to run a simple example same as the react-context:
app.js
import React, { Component } from 'react';
import AppManger from './components/AppManger';
import './App.css';
export const ThemeContext = React.createContext({a1:'a1'});
class App extends Component {
render() {
return (
<div className="App">
<h1>Manage Storefront Services Products</h1>
<ThemeContext.Provider value="dark">
<AppManger />
</ThemeContext.Provider>
</div>
);
}
}
export default App;
AppManger.js(has no context reference)
import React, { Component } from 'react'
import SearchBar from './SearchBar';
export default class AppManger extends Component {
constructor(props) {
super(props);
this.onSearchBarChange = this.onSearchBarChange.bind(this);
this.state = {
searchValue: '',
errorLoading: false,
errorObj: null,
}
}
onSearchBarChange(e) {
e.persist();
this.setState({ searchValue: e.target.value });
}
render() {
return (
<div>
Log out
<SearchBar onSearchBarChange={this.onSearchBarChange} inAttrView={this.state.onAttrPage} />
</div>
)
}
}
And the SearchBar.js where I want to use Context:
import React, { Component } from 'react';
import ThemeContext from '../App';
export default class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
showAttrModal: false
};
};
componentDidMount(){
console.log(this.context); //{}
}
render() {
const contextType = ThemeContext;
console.log(contextType); //{}
return (
<div>
{contextType} /*'contextType' is not defined no-undef */
<input type="text" style={searchBoxStyle} className="form-control" onChange={this.props.onSearchBarChange} placeholder="Search for..." id="sku" name="sku" />
</div>
)
}
}
If I run the app I get Line 44: 'contextType' is not defined no-undef in SearchBar.js if I remove this line I get {} when I logging the this.context.
You aren't correctly using context, as you need to define it as a static property of the class and import it as a named import since you have exported it as a named import
import { ThemeContext } from '../App';
export default class SearchBar extends Component {
constructor(props) {
super(props);
this.state = {
showModal: false,
showAttrModal: false
};
};
static contextType = ThemeContext;
componentDidMount(){
console.log(this.context); //{}
}
render() {
console.log(this.contextType); //{}
return (
<div>
{contextType} /*'contextType' is not defined no-undef */
<input type="text" style={searchBoxStyle} className="form-control" onChange={this.props.onSearchBarChange} placeholder="Search for..." id="sku" name="sku" />
</div>
)
}
}
You imported App instead of ThemeContext.
use import { ThemeContext } from '../App.js;
Here problem:
componentDidMount() {
console.log(this.context);
}
Here can't find this.context variable.
static contextType =
To
const contextType =
I'm having issues with a passed down prop. I'm trying to render an array of objects in a list. However, the prop returns the results, and then immediately turns it to 'undefined'. Open dev tools to see result in console.
Parent component:
import React, { Component } from 'react';
import './App.css';
import { SearchBar } from '../SearchBar/SearchBar.js';
import { SearchResults } from '../SearchResults/SearchResults.js';
import { Playlist } from '../Playlist/Playlist.js';
class App extends React.Component {
constructor(props){
super(props);
this.state = {
searchResults: [
{
id: 2011,
name: 'What Makes A Man',
artist: 'Man As Machine',
album: 'Nothing but a thing'
},
{
id: 2056,
name: 'Pushpin',
artist: 'Man As Machine',
album: 'Patterns'
},
{
id: 2099,
name: 'Zombie',
artist: 'Man As Machine',
album: 'Patterns'
}
],
playlistName: ''
}
}
render() {
return (
<div>
<h1>Ja<span className="highlight">mmm</span>ing</h1>
<div className="App">
<SearchBar />
<div className="App-playlist">
<SearchResults searchResults={this.state.searchResults}/>
<Playlist />
</div>
</div>
</div>
);
}
}
export default App;
the first child component:
import React from 'react';
import './SearchResults.css';
import { Tracklist } from '../Tracklist/Tracklist.js';
export class SearchResults extends React.Component {
render () {
return (
<div className="SearchResults">
<h2>Results</h2>
<Tracklist tracks={this.props.searchResults}/>
</div>
)
}
}
The destination child component:
import React from 'react';
import './Tracklist.css';
import { Track } from '../Track/Track.js';
export class Tracklist extends React.Component {
constructor(props) {
super(props);
}
renderTrackList() {
let properties = this.props.tracks;
if (properties === undefined){
return <h3>Sorry, we found no results</h3>
} else {
properties.forEach( track => {
console.log(track);
return <Track key={track.id} track={track} />;
})
}
}
render () {
return (
<div className="TrackList">
{this.renderTrackList()}
</div>
)
}
}
I have attached the other components just for clarity. They are as follows:
playlist:
import React from 'react';
import './Playlist.css';
import { Tracklist } from '../Tracklist/Tracklist.js';
export class Playlist extends React.Component {
render() {
return (
<div className="Playlist">
<input defaultValue='New Playlist'/>
<Tracklist />
<a className="Playlist-save">SAVE</a>
</div>
)
}
}
searchBar:
import React from 'react';
import './SearchBar.css';
export class SearchBar extends React.Component {
render() {
return (
<div className="SearchBar">
<input placeholder="Enter A Song, Album, or Artist" />
<a>SEARCH</a>
</div>
);
}
}
Track:
import React from 'react';
import './Track.css';
export class Track extends React.Component {
renderAction (isRemoval) {
if (this.props.isRemoval){
return <a className="Track-action" onClick={this.removeTrack}>-</a>
} else {
return <a className="Track-action" onClick={this.addTrack}>+</a>
}
}
render () {
return (
<div className="Track">
<div className="Track-information">
<h3>{this.props.track.name}</h3>
<p>{this.props.track.artist} | {this.props.track.album}</p>
</div>
<a className="Track-action">{this.renderAction}</a>
</div>
)
}
}
Please note that this is still a work in progress. So a lot of the detail and event handlers still need to be programmed.
Instead of
properties.forEach( track => {
console.log(track);
return <Track key={track.id} track={track} />;
})
write
return properties.map( track => {
console.log(track);
return <Track key={track.id} track={track} />;
})
OR
.map without return
return properties.map( track => (
<Track key={track.id} track={track} />
))
I have no idea how to make my app work.
I have a component ContactAdd that onClick must render component ModalWindow. ModalWindow has a parameter isOpened={this.state.open}. How to control this state from parent component?
import React from 'react';
import ContactAddModal from './ContactAddModal.jsx';
import './ContactAdd.css';
export default class ContactAdd extends React.Component {
constructor(props){
super(props);
}
render() {
return (
<div className="add-contact" onClick={ ??????? }>
<img src="./img/add.png" />
<ContactAddModal/>
</div>
)
}
}
import React from 'react';
export default class ContactAddModal extends React.Component {
constructor(props){
super(props);
this.state = {
show: false,
};
this.handleCloseModal = this.handleCloseModal.bind(this);
}
handleCloseModal () {
this.setState({ show: false });
}
render() {
return (
<div className="modal" isOpened={this.state.show}>
<button onClick={this.handleCloseModal}>Close Modal</button>
</div>
)
}
Making the modal a stateless component might be simpler here. The tradeoff being that you would have to handle the closing for every modal, which I think is acceptable. This answer is just an option and by no means an absolute truth.
It could look something like that
export default class ContactAdd extends React.Component {
constructor(props){
super(props);
this.state = {
showModal: true
};
this.hideModal = this.hideModal.bind(this);
}
hideModal() {
this.setState({
showModal: false
});
}
render() {
return (
<div className="add-contact">
<img src="./img/add.png" />
<ContactAddModal handleClose={this.hideModal} isOpened={this.state.showModal} />
</div>
)
}
}
Now the modal:
export default class ContactAddModal extends React.Component {
render() {
return (
<div className="modal" isOpened={this.props.isOpened}>
<button onClick={this.props.handleClose}>Close Modal</button>
</div>
)
}
having a serious challenge with my React/Redux authorization setup and I'm at a loss. Current error is:
HomeHeader.js?8595:26 Uncaught ReferenceError: dispatch is not defined
There's a lot wrong here, and any help would be appreciated.
I'm creating two authorization components, one to register and one to login. The AuthorizationLogin component is what I'm working on first.
I don't know how to get this to pass the event info it grabs form the form fields, put in the variable creds, and then on up through the HomeHeader component, and then again up to the HomePage container. Do I put all of the authorization components into one enormous HomeHeader component?
Here's the main code and flow. Code isn't loading right into StackOverflow for some reason.
HomePage.js
import React from 'react';
import {connect} from 'react-redux';
import * as actions from '../../../actions/homeEventFormActions';
import HomeHeader from '../homeHeader/HomeHeader';
import HomeEventForm from '../homeEventForm/HomeEventForm';
class HomePage extends React.Component {
constructor(props) {
super(props);
}
render() {
const { dispatch } = this.props;
return (
<div>
< HomeHeader />
< HomeEventForm
onSubmit={this.props.onSubmit}
/>
</div>
);
}
}
function mapStateToProps(state) {
return {
homeEventForm: state.homeEventForm
};
}
function mapDispatchToProps(dispatch) {
return {
onSubmit: (eventName) => dispatch(actions.createEventButton(eventName)),
};
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(HomePage);
HomeHeader.js
import React, { Component, PropTypes } from 'react';
import AuthorizeLogin from '../../Authorization/AuthorizeLogin';
import AuthorizeRegister from '../../Authorization/AuthorizeRegister';
import { loginUser } from '../../../actions/authorizationActions';
class HomeHeader extends React.Component {
constructor() {
super();
}
_handleChange(eventKey) {
...
<AuthorizeLogin
onLoginClick={ (creds) => dispatch(loginUser(creds))}
/>
...
}
return;
}
render() {
const { dispatch } = this.props;
return (
...
<Modal.Header closeButton onClick={ ()=> this._handleChange(5)}>
...
);
}
}
export default HomeHeader;
AuthorizeLogin.js
import React from 'react';
class AuthorizeLogin extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {};
this._login = this._login.bind(this);
}
_login(e) {
e.preventDefault;
const email = this.refs.email;
const password = this.refs.password;
const creds = { email: email.value.trim(), password: password.value.trim() };
this.props.onLoginClick(creds);
}
render() {
return (
<Form horizontal onSubmit={this._login}>
<h4 className="authEmailText">Login with your email</h4>
<input type="email" placeholder="urawesome#example.com" ref='email' />
<input type="password" placeholder="Password" ref='password' />
</Form>
);
}
}
export default AuthorizeLogin;
All the actions should be dispatched from container. In this case, the container should have the dispatch.
function mapDispatchToProps(dispatch) {
return {
onSubmit: (eventName) => dispatch(actions.createEventButton(eventName)),
onLogin: (creds) => dispatch(loginUser(creds)),
};
}
The onLogin should be passed to downstream components via props:
<HomeHeader onLogin={this.props.onLogin} />
<AuthorizeLogin
onLoginClick={this.props.onLogin}
/>