adding child inside function in react js - javascript

My task is to add h1 inside the div with input and button after clicking it. I don`t know if it is possible to add child inside function and if it is not how else i can do this
import React from "react";
class ToDo extends React.Component {
addTask() {
var inputText = document.getElementById("input").value;
}
render() {
return (
<div>
<input id="input" type="text" ref={input => (this.textInput = input)} />
<button onClick={this.addTask}>Add</button>
</div>
);
}
}
export default ToDo;

class ToDo extends React.Component {
state = {expanded: false};
render() {
const {expanded} = this.state;
if(expanded) {
return (
<div>
<h1>
<input .../>
</h1>
<button onClick={() => this.setState({expanded: false})>cancel</button>
</div>
);
} else {
return <div onClick={() => this.setState({expanded: true})>add task</div>
}
}
}
I left the internal "schematic", you need to add your elements and handler, just wanted to demonstrate the principal

Related

React: Render and link toggle button outside the class

I have the following example where the toggleComponent.js is working perfectly.
The problem here is that I don't want to render the <ContentComponent/> inside the toggle, rather I want the opposite, I want to toggle the <ContentComponent/> that will be called in another component depending on the state of the toggle.
So the <ContentComponent/> is outside the toggleComponent.js, but they are linked together. So I can display it externally using the toggle.
An image to give you an idea:
Link to funtional code:
https://stackblitz.com/edit/react-fwn3rn?file=src/App.js
import React, { Component } from "react";
import ToggleComponent from "./toggleComponent";
import ContentComponent from "./content";
export default class App extends React.Component {
render() {
return (
<div>
<ToggleComponent
render={({ isShowBody, checkbox }) => (
<div>
{isShowBody && <h1>test</h1>}
<button onClick={checkbox}>Show</button>
</div>
)}
/>
<ToggleComponent
render={({ isShowBody, checkbox }) => (
<div>
{isShowBody && (
<h1>
<ContentComponent />
</h1>
)}
<button onClick={checkbox}>Show</button>
</div>
)}
/>
</div>
);
}
}
Bit tweaked your source.
Modified ToggleComponent
import React from "react";
export default class ToggleComponent extends React.Component {
constructor() {
super();
this.state = {
checked: false
};
this.handleClick = this.handleClick.bind(this);
}
handleClick = () => {
this.setState({ checked: !this.state.checked });
this.props.toggled(!this.state.checked);
};
checkbox = () => {
return (
<div>
<label>Toggle</label>
<span className="switch switch-sm">
<label>
<input type="checkbox" name="select" onClick={this.handleClick} />
<span />
</label>
</span>
</div>
);
};
render() {
return this.checkbox();
}
}
Added OtherComponent with ContentComponent inside.
import React, { Component } from "react";
import ContentComponent from "./content";
export default class OtherComponent extends React.Component {
render() {
return <div>{this.props.show ? <ContentComponent /> : null}</div>;
}
}
Separated as per your requirement.
Modified App
import React, { Component, PropTypes } from "react";
import ToggleComponent from "./toggleComponent";
import OtherComponent from "./otherComponent";
export default class App extends React.Component {
constructor() {
super();
this.toggled = this.toggled.bind(this);
this.state = { show: false };
}
toggled(value) {
this.setState({ show: value });
}
render() {
return (
<div>
<ToggleComponent toggled={this.toggled} />
<OtherComponent show={this.state.show} />
</div>
);
}
}
Working demo at StackBlitz.
If you want to share states across components a good way to do that is to use callbacks and states. I will use below some functional components but the same principle can be applied with class based components and their setState function.
You can see this example running here, I've tried to reproduce a bit what you showed in your question.
import React, { useState, useEffect, useCallback } from "react";
import "./style.css";
const ToggleComponent = props => {
const { label: labelText, checked, onClick } = props;
return (
<label>
<input type="checkbox" checked={checked} onClick={onClick} />
{labelText}
</label>
);
};
const ContentComponent = props => {
const { label, children, render: renderFromProps, onChange } = props;
const [checked, setChecked] = useState(false);
const defaultRender = () => null;
const render = renderFromProps || children || defaultRender;
return (
<div>
<ToggleComponent
label={label}
checked={checked}
onClick={() => {
setChecked(previousChecked => !previousChecked);
}}
/>
{render(checked)}
</div>
);
};
const Holder = () => {
return (
<div>
<ContentComponent label="First">
{checked => (
<h1>First content ({checked ? "checked" : "unchecked"})</h1>
)}
</ContentComponent>
<ContentComponent
label="Second"
render={checked => (checked ? <h1>Second content</h1> : null)}
/>
</div>
);
};
PS: A good rule of thumb concerning state management is to try to avoid bi-directional state handling. For instance here in my example I don't use an internal state in ToggleComponent because it would require to update it if given checked property has changed. If you want to have this kind of shared state changes then you need to use useEffect on functional component.
const ContentComponent = props => {
const { checked: checkedFromProps, label, children, render: renderFromProps, onChange } = props;
const [checked, setChecked] = useState(checkedFromProps || false);
const defaultRender = () => null;
const render = renderFromProps || children || defaultRender;
// onChange callback
useEffect(() => {
if (onChange) {
onChange(checked);
}
}, [ checked, onChange ]);
// update from props
useEffect(() => {
setChecked(checkedFromProps);
}, [ checkedFromProps, setChecked ]);
return (
<div>
<ToggleComponent
label={label}
checked={checked}
onClick={() => {
setChecked(previousChecked => !previousChecked);
}}
/>
{render(checked)}
</div>
);
};
const Other = () => {
const [ checked, setChecked ] = useState(true);
return (
<div>
{ checked ? "Checked" : "Unchecked" }
<ContentComponent checked={checked} onChange={setChecked} />
</div>
);
};

How to add a string to a string list in a todo list react

Hi everyone am trying to add string values from this.state.todo below to the array (list) below so that i can loop through them. I need assistance
import React, {Component} from "react";
import "./styles.css";
class App extends Component {
state = {
todo: '',
list: []
}
changeHandler = (event) => {
this.setState({
todo: event.target.value
});
}
submitHandler = (event) => {
event.preventDefault()
this.setState({
list: [...this.state.list, this.state.todo]
});
}
render(){
return (
<div className="App">
<input type="text" onChange = {this.changeHandler} />
<button onSubmit={this.submitHandler}> Submit </button>
{console.log(this.state)}
</div>
);
}
}
export default App
you could change button event to onClick instead of onSubmit.
Or
Else If you are using onSubmit you should wrap the component with form
return (
<div className="App">
<form onSubmit={this.submitHandler}>
<input type="text" onChange = {this.changeHandler} />
<button > Submit </button>
{console.log(this.state)}
</form>
</div>
)
You need to put state in constructor and bind function:
class App extends Component {
constructor(props) {
super(props)
this.state = {
todo: '',
list: []
}
this.changeHandler = this.changeHandler.bind(this)
this.submitHandler = this.submitHandler.bind(this)
}
...
}

How can I take the value of an Input and store it in another component?

I am new to react and I have a problem trying to take the information submitted in an input and return it as output outside the nav component, where it sits. I want the output to return to the Content component but I am having a hard time trying to figure out how to do that. Trying to return it as a prop returns as undefined. I have read the documentation and tried to find answer in videos but nothing seems to be solving the problem. Can anyone point me in the right direction?
// this is the root component
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
userInput: ''
}
}
handleChange = (e) => {
this.setState({
userInput: e.target.value
})
}
render() {
const { userInput } = this.state
return (
<div className="recipes">
<Nav />
<Content userInput={this.state.userInput} changed={this.handleChange} />
</div>
)
}
}
// this is where the input is stored and where I want to take its value and return it to the the Content Component
class Nav extends React.Component {
state = {
userInput: ''
}
handleChange = (e) => {
this.setState({
userInput: e.target.value
})
}
render() {
return (
<nav className="nav">
<h1 className="title" >Nourish</h1>
<h2 className="title" >{this.state.userInput}</h2>
<input type="text" className="input" onChange={this.handleChange} />
</nav>
)
}
}
// this is where I want to output the value to
const Content = (props) => {
console.log(props.userInput)
return (
<h2 className="main"> {props.userInput} </h2>
)
}
you can create a simple input component but the value and event handlers come from the parent as props
look at this example
import React, { useState } from 'react'
import Input from './Input'
const App = () => {
const [InputOneValue, setInputOnValue] = useState("")
const [InputTwoValue, setInputTwoValue] = useState("")
const InputOneChangeHandler = (value) => {
setInputOneValue(value)
}
const InputTwoChangeHandle = (value) => {
setInputTwoValue(value)
}
const onSubmitHanlder = () {
// InputOneValue
// InputTwoValue
}
return (
<form onSubmit={submitHandler}>
<Input value={InputOneValue} changeHandler={InputOneChangeHandler}
<Input value={InputTwoValue} changeHandler={InputTwoChangeHandler}
</form>
)
}
export default App
and this is you Input component
const Input = (props) => {
return <input value={props.value} onChange={props.changeHandler} />
}
export default Input
You dont need to write handle change and not needed to store userInput in Nav. store directly in App.js . so in Nav instead of this.handleChange use this.props.changed this helps you store userInput in App then you can pass the data as props.
// this is the root component
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
userInput: ""
}
}
handleChange = (e) => {
this.setState({
userInput: e.target.value
})
}
render() {
const { userInput } = this.state
return (
<div className="recipes">
<Nav userInput={this.state.userInput} />
<Content userInput={this.state.userInput} changed={this.handleChange} />
</div>
)
}
}
class Nav extends React.Component {
render() {
return (
<nav className="nav">
<h1 className="title" >Nourish</h1>
<h2 className="title" >{this.state.userInput}</h2>
<input type="text" className="input" onChange={this.props.changed} />
</nav>
)
}
}
// this is where I want to output the value to
const Content = (props) => {
console.log(props.userInput)
return (
<h2 className="main"> {props.userInput} </h2>
)
}

Lifting message up in REACT

I want to do a real time searching in React. How can I lift the message up from child to parent? Or how can I pass a parent handler to children through props to handle the event?
parent class:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
activities: activities,
filteredActivities: activities,
};
this.handleSearchChange = this.handleSearchChange.bind(this);
}
filterActivity = searchText => {
return this.state.activities
.filter(activity => {
if(activity.content.toLowerCase().includes(
searchText.toLowerCase())
){
return true;
}
return false;
});
}
handleSearchChange = event => {
this.setState({
filteredActivities: this.filterActivity(event.target.value)
});
};
render() {
const filteredActivities = this.props.filteredActivities;
return(
<div className="notificationsFrame">
<div className="panel">
<Header name={this.props.name} />
<SearchBar onChange={this.handleSearchChange} />
<Content activities={this.state.filteredActivities} />
</div>
</div>
);
}
}
Child class:
class SearchBar extends React.Component {
onChangeHandler = event => {
console.log(event.target.value);
}
render() {
return (
<div className="search-bar" >
<input type="text" onChange={this.onChangeHandler} />
</div>
);
}
}
I want to pass the event.target.value to handleSearchChange. if I put the code of class Searchbar to class App, I can perform a real time searching very good. But I can't put them into two components. I want to make them into two components. Thanks a lot.
Should be as simple as this:-
Child class:
class SearchBar extends React.Component {
onChangeHandler = event => {
this.props.inputChanged(event.target.value);
}
render() {
return (
<div className="search-bar" >
<input type="text" onChange={this.onChangeHandler} />
</div>
);
}
}
Parent class:
handleSearchChange = inputValue => {
this.setState({
filteredActivities: this.filterActivity(inputValue)
});
};
JSX of parent class:
<SearchBar inputChanged={this.handleSearchChange} />
since you're already passing the function's reference as a prop you can access it using this.props.propName and call it.
class SearchBar extends React.Component {
/* onChangeHandler = event => {
console.log(event.target.value);
} */
render() {
const { onChange } = this.props;
return (
<div className="search-bar" >
<input type="text" onChange={onChange} />
</div>
);
}
}
You can try this, as you already took event as a parameter in parent class for handleSearchChange method

How can i pass props through methods inside components?

i have a react component named "List" that renders smaller components "Post" using a button through method "Addpost()" that takes 2 props from the input form. I have saved the input in 2 varables but i don't know how to pass these props to the Addpost() method inside the return of List's render().
//=========== List component ==============
class List extends React.Component{
renderPost(title,content){
return(
<Post titolo={title} contenuto={content}/>
);
}
renderPost just render the Post component in a in the HTML
addPost(title,content){
title = document.getElementById("inputTitle").value;
content = document.getElementById("inputContent").value;
console.log(title, content)
this.renderPost(title,content);
}
addPost should take the input value and use renderPost to render the Post component with that title and content
render(){
return(
<div>
{this.renderPost("testTitle","testContent")}
<form>
Title:<br></br>
<input type="text" id="inputTitle"/><br></br>
Content:<br></br>
<input type="text" id="inputContent"/>
</form><br></br>
<button className="square"
how can i make this work? title and content are not defined
onClick={() =>
this.addPost(title,content)
Add Post!
</button>
</div>
);
}
}
//=========== Post component ==============
class Post extends React.Component {
render() {
return (
<li className="w3-padding-16">
<img src="/w3images/workshop.jpg" alt="Imagedf" className="w3-left w3-margin-right" />`enter code here`
<span className="w3-large">
{this.props.titolo}
</span><br></br>
<span>{this.props.contenuto}</span>
</li>
);
}
}
Basically, whenever you're dealing with forms and inputs, you would use refs.
App.js
import React from 'react';
import logo from './logo.svg';
import './App.css';
import PostList from './components/PostList'
import AddPostForm from './components/AddPostForm'
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
posts: [] //state is handled here
}
this.addPost = this.addPost.bind(this)
}
addPost(title, content) {
let newPost = { title, content }
this.setState(({ posts }) => { return { posts: [...posts, newPost] } } )
}
render() {
const { posts } = this.state
return (
<div>
<AddPostForm onNewPost={this.addPost} /> //we pass addPost to the component
<br />
<PostList posts={posts} />
</div>
);
}
}
export default App;
Post.js
import React from 'react';
function Post({titolo, contenuto}) {
return (
<li className="w3-padding-16">
<img src="/w3images/workshop.jpg" alt="Imagedf" className="w3-left w3-margin-right" />`enter code here`
<span className="w3-large">
{titolo}
</span><br></br>
<span>{contenuto}</span>
</li>
);
}
export default Post
AddPostForm.js
import React from 'react';
const addPostForm = ({onNewPost = f => f}) => { //onNewPost method is passed by props from the parent
let _titleInput, _contentInput //these are our refs, see the docs for more information
const submit = (e) => {
e.preventDefault()
onNewPost(_titleInput.value, _contentInput.value) //here we call the addPost function that was passed to the component
_titleInput.value = '' //empty the inputs
_contentInput.value = ''
_titleInput.focus() //set focus
}
return (
<form onSubmit={submit}>
Title:<br></br>
<input type="text" ref={title => _titleInput = title} /><br></br>{/* Note the ref attribute */}
Content:<br></br>
<input type="text" ref={content => _contentInput = content} />
<button className="square">Add a new post</button>
</form>
)
}
export default addPostForm
PostList.js
import React from 'react';
import Post from './Post';
const PostList = ({ posts=[] }) => {
return (
<div className="post-list">
{
posts.map((post, index) =>
<Post key={index} titolo={post.title} contenuto={post.content} />
)
}
</div>
)
}
export default PostList
And the result:
edit
renderPost just render the Post component in a in the HTML
state = { inputTitle: '', inputContent: '' }
addPost(title,content){
title = document.getElementById("inputTitle").value;
content = document.getElementById("inputContent").value;
console.log(title, content)
this.renderPost(title,content);
}
addPost should take the input value and use renderPost to render the Post
component with that title and content
render(){
return(
<div>
{this.renderPost("testTitle","testContent")}
<form>
Title:<br></br>
<input type="text" value={this.inputTitle} onChnage={event => setState({ inputTitle: event.target.value }) }><br></br>
Content:<br></br>
<input type="text" value={this.inputContent} onChnage={event => setState({ inputContent: event.target.value }) } />
</form><br></br>
<button className="square"
on click function
onClick={() =>
this.addPost(this.inputTitle,this.inputContent)
Add Post!
</button>
</div>
);
}
}

Categories

Resources