Lifting message up in REACT - javascript

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

Related

Output data from form on the page react

I am writing todo app. There are main files in my directory now:
App (rendering main page with header and buttons)
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = { triggerText: 'Create a task' };
}
propTypes = {
triggerText: PropTypes.string.isRequired,
handleSubmit: PropTypes.object.isRequired,
};
render() {
const { triggerText } = this.state;
const { handleSubmit } = this.props;
return (
<div className="App">
<header className="App-header">
<h1>To Do List</h1>
<div id="tasksList">
<span className="tasks active">Tasks</span>
</div>
<div id="categoriesList">
<span className="categories">Categories</span>
</div>
<div>
<Container triggerText={triggerText} onSubmit={handleSubmit} /> // creates modal dialog and uses TodoForm
</div>
</header>
<div id="container" className="container">
<TodoBox tasks={[]}/>
</div>
</div>
);
}
}
TodoForm (create a form)
export default class TodoForm extends React.Component {
constructor(props) {
super(props);
this.state = { value: '', tasks: [] };
}
propTypes = {
handleSubmit: PropTypes.object.isRequired,
}
handleRemove = (currentTaskId) => (e) => {
e.preventDefault();
const { tasks } = this.state;
this.setState({ tasks: tasks.filter(({ id }) => id !== currentTaskId) });
};
handleChange = (e) => {
e.preventDefault();
this.setState({ value: e.target.value });
}
handleSubmit = (e) => {
e.preventDefault();
const { value, tasks } = this.state;
const newTask = { id: uniqueId(), text: value };
this.setState({ value: '', tasks: [newTask, ...tasks] });
}
render() {
const { value } = this.state;
return (
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="text"><strong>Create a task</strong></label>
<input
type="text"
onChange={this.handleChange}
value={value}
required
className="form-control"
id="text"
placeholder="I am going..."
/>
</div>
<div className="form-group">
<button type="submit" className="form-control btn btn-primary">Add</button>
</div>
</form>
);
}
}
TodoBox (generating list of tasks)
class Item extends React.Component {
propTypes = {
onRemove: PropTypes.object.isRequired,
task: PropTypes.string.isRequired,
};
render() {
const { task, onRemove } = this.props;
return (
<div className="row">
<div>
<button type="button" className="btn btn-primary" onClick={onRemove}>-</button>
</div>
<div className="col-10">{task.text}</div>
</div>
);
}
}
export default class TodoBox extends React.Component {
constructor(props) {
super(props);
}
propTypes = {
tasks: PropTypes.string.isRequired,
}
render() {
const { tasks } = this.props;
return (
<div className="item">
{tasks.map((task) => (
<div key={task.id}>
<Item task={task} onRemove={this.handleRemove} />
<hr />
</div>
))}
</div>
);
}
}
And the question is: how I can pass the state from TodoForm to TodoBox in App (it is initialize as an empty array now). I want to output tasks at the bottom of the same page in container after header element.
You can create a function (addTodo) in App component and pass it down to the TodoForm component. In TodoForm component you can invoke the addTodo function from props and send the todoValue as arguments props.addTodo(todoValue). In addTodo function in App component you can update the todoValue to state. Once you update the state it will re-render the App component, then the TodoBox component will call with the updated todoValue value.
Note: But it is not best practice. The best practice is to use React Context

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>
)
}

adding child inside function in react js

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

ReactJS - How to change a component's state based on another component

Im trying to update a component's state when a different component's state changes.
Here is the main component that contains the form:
class IpsumForm extends React.Component {
state = {
character: 'All',
paragraphs: 1,
ipsumDisplayed: false
};
handleInputChange = (e) => {
const target = e.target;
this.setState({ paragraphs: target.value });
};
handleSelectChange = (e) => {
const target = e.target;
this.setState({ character: target.value });
};
handleReset = (e) => {
this.setState({
character: 'All',
paragraphs: 1,
ipsumDisplayed: false
});
};
handleSubmit = (e) => {
e.preventDefault();
this.setState({
ipsumDisplayed: true
});
};
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<p>Select Your Character:</p>
<select
value={this.state.character}
onChange={this.handleSelectChange}
name="characterPick"
>
<option value="All">All</option>
<option value="Michael">Michael</option>
<option value="Dwight">Dwight</option>
<option value="Jim">Jim</option>
<option value="Andy">Andy</option>
<option value="Creed">Creed</option>
</select>
<div className="length">
<p>How Many Paragraphs?</p>
<input
onChange={this.handleInputChange}
name="paragraphLength"
type="text"
/>
</div>
<hr />
<input
id="submit"
type="submit"
value="Bibity Boppity Give Me The Zoppity"
/>
<button onClick={this.handleReset}>Reset</button>
</form>
<br />
<IpsumText
person={this.state.character}
length={this.state.paragraphs}
displayed={this.state.ipsumDisplayed}
/>
</div>
);
}
}
export default IpsumForm;
And here is the component that I would like to return the ipsum within a textbox:
class IpsumText extends React.Component {
state = {
value: ''
};
handleValueChange = (e) => {
console.log(data.quote1);
this.setState({
value: data.quote1
});
};
render() {
let character = this.props.person;
let paragraphs = this.props.length;
let displayed = this.props.displayed;
return (
<div className="returned-ipsum">
<textarea value={this.state.value} onChange={this.handleValueChange} />
</div>
);
}
}
export default IpsumText;
The code I have now doesn't work because a state change from the IpsumForm doesn't cause the textarea onChange handler to run in the IpsumText
I'm wondering if there is a way to do this other than using a lifecycle method because it seems like i'm just overthinking it
Here's a very simple way of looking at it:
class App extends React.Component {
state = {
firstState: 1,
}
handleStateUpdate = () => {
this.setState(prev => ({
firstState: prev.firstState + 1
}))
}
render() {
console.log(this.state.firstState)
return (
<Foo handleStateUpdate={this.handleStateUpdate} />
)
}
}
class Foo extends React.Component {
state = {
otherState: 1,
}
handleLocalStateUpdate = () => {
this.props.handleStateUpdate()
this.setState(prev => ({
otherState: prev.otherState + 1
}))
}
render() {
return <button onClick={() => this.handleLocalStateUpdate()}>Click here!</button>
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<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='app'></div>
What this is doing is passing down a function from the parent that updates the parent state, down to the child component. Once you define a function that updates the state of the child component, you can call that passed down function to also update the parent state.
Hopefully, the principle of doing this helps with the issue you're facing.
Here's a link to the code in case you wanna mess with it:
CodePen

Fired method on input with other component with event

its possible to fired event like on example :
const Tet = (props) => {
return (
<div>
<label>id:<input onChange= **FIRED RR METHOD** type="text"/></label>
</div>
);
}
And my component
class TContainer extends React.Component {
rr(obj, ev) {
console.log(obja, ev.target.value));
}
render() {
return (
<Tet lala={this.state.dataList} rr={this.rr.bind(this)}/>
)
}
How to call method with event.target.value and passing normal attr.
If you just want to propagate props, the easiest way to do it is:
const Tet = ({ onChange }) => {
return (
<div>
<input type="text" onChange={onChange} />
</div>
)
}
class TetContainer extends React.Component {
constructor() {
super()
this.handleChange = this.handleChange.bind(this)
}
handleChange(event) {
console.log(event.target.value)
}
render() {
return <Tet onChange={this.handleChange} />
}
}
ReactDOM.render(
<TetContainer />,
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>
If you want to pass custom arguments then pass a new function to onchange which call your rr function with your custom arguments like this
const Tet = (props) => {
return (
<div>
<label>id:<input onChange={(e) => {props.rr(obj,e)}} type="text"/></label>
</div>
);
}

Categories

Resources