merge values from pluck and combineLatest inside map rxjs - rxjs

I've a prop of addHandler passed to AddTodo component from App.js. Then inside AddTodo handler I'm not sure how do I combine pluck and map so that I've value from pluck as well as combineLatest merged inside map
Here's my code
App.js
import React from 'react';
import { componentFromStream , createEventHandler } from "recompose";
import { combineLatest } from "rxjs";
import { map, tap } from "rxjs/operators";
import AddTodo from './AddTodo/AddTodo';
import Todos from './Todos/todos';
// import User from './User/User';
const App = componentFromStream(prop$ => {
const { handler: onAddHandler, stream: clickStream } = createEventHandler();
const value$ = clickStream.pipe( tap(input =>
console.warn(input)
));
return combineLatest(prop$, value$).pipe(map(([props, value]) => <div>
<AddTodo onAddHandler={onAddHandler} />
{/* <input placeholder="Add TODO" onChange={handler} /> */}
<Todos todo={value} />
</div>));
});
export default App;
AddTodo.js
import React from "react";
import { combineLatest } from "rxjs";
import { componentFromStream, createEventHandler } from "recompose";
import { pluck, map, startWith, tap } from "rxjs/operators";
const AddTodo = componentFromStream(prop$ => {
const {
handler: onChangeHandler,
stream: inputStream
} = createEventHandler();
const value$ = inputStream.pipe(
map(e => e.target.value),
startWith("")
);
return combineLatest(prop$, value$).pipe(
map(([props, value]) => (
<div>
<input
type="text"
placeholder="Add Todo..."
onChange={onChangeHandler}
/>
<button onClick={() => {}}>Add todo</button>
{/* <button onClick={() => onAddHandler(value)}>Add todo</button> */}
</div>
))
);
});
export default AddTodo;
Inside AddTodo.js inside map I probably I'm looking for something like
return combineLatest(prop$, value$).pipe(
pluck('onAddHandler'),
// and use this value plus the belo values inside map
map(([props, value]) => (

all your need to do is move pluck inside combineLatest which look like this, then you
should get the onAddHandler in the map operator:
return combineLatest(prop$.pipe(pluck('onAddHandler')), value$).pipe(
map(([onAddHandler, value]) => (
<div>
<input
type="text"
placeholder="Add Todo..."
onChange={onChangeHandler}
/>
<button onClick={() => {}}>Add todo</button>
{/* <button onClick={() => onAddHandler(value)}>Add todo</button> */}
</div>
))
);

Related

Form is not rendered

I'm making a todo app and using useState to pass value to the form then submit the todo but for some reasons my todo form is not render and i don't know what is missing in my codes, please help me to check! Thank you so much!
import React, { useState } from "react";
function Todo({ todo, index }) {
console.log("hiiii");
return (
<div>
<p>{todo.text}</p>
</div>
);
}
function todoForm(addTodo) {
const [value, setValue] = useState("");
handleSubmit = (e) => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="add new todo"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
</form>
</div>
);
}
function App() {
const [todos, setTodos] = useState([
{
text: "eat lunch",
isCompleted: false
},
{
text: "do homework",
isCompleted: false
},
{
text: "go to school",
isCompleted: false
}
]);
addTodo = (text) => {
console.log("hey");
const newTodos = [...todos, { text }];
setTodos(newTodos);
};
return (
<div>
<div>
{todos.map((todo, index) => {
return <Todo key={index} index={index} todo={todo} />;
})}
</div>
<div>
<todoForm addTodo={addTodo} />
</div>
</div>
);
}
export default App;
Link sandbox: https://codesandbox.io/s/serverless-bash-ef4hk?file=/src/App.js
JSX tags must be uppercased in order to be properly parsed by the compiler as a React component.
Instead of todoForm, use TodoForm.
Capitalized types indicate that the JSX tag is referring to a React component. These tags get compiled into a direct reference to the named variable, so if you use the JSX expression, Foo must be in scope.
From: https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type
Also, you need to destructure props inside TodoForm in order to gain access to addTodo:
// Bad
function TodoForm(addTodo) {...}
// Good
function TodoForm({addTodo}) {...}
You should also assign you handlers to consts:
// Bad
addTodo = (text) => {...};
// Good
const addTodo = (text) => {...};
your problem is solved it
APP.JS
import React, { useState } from "react";
function Todo({ todo, index }) {
console.log("hiiii");
return (
<div>
<p>{todo.text}</p>
</div>
);
}
function todoForm(addTodo) {
const [value, setValue] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
if (!value) return;
addTodo(value);
setValue("");
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="add new todo"
value={value}
onChange={(e) => {
setValue(e.target.value);
}}
/>
</form>
</div>
);
}
function App() {
const [todos, setTodos] = useState([
{
text: "eat lunch",
isCompleted: false
},
{
text: "do homework",
isCompleted: false
},
{
text: "go to school",
isCompleted: false
}
]);
const addTodo = (text) => {
console.log("hey");
const newTodos = [...todos, { text }];
setTodos(newTodos);
};
return (
<div>
<div>
{todos.map((todo, index) => {
return <Todo key={index} index={index} todo={todo} />;
})}
</div>
<div>
{todoForm(addTodo)}
</div>
</div>
);
}
export default App;

React ajax call when button onClick event using hooks

import React, { useState, useEffect } from "react";
import axios from "axios";
function App() {
const [contact, setContact] = useState({
fName: "",
lName: "",
email: ""
});
function handleClick() {
const res = axios.get("url");
}
useEffect(()=>{
handleClick();
})
return (
<div className="container">
<h1>
Hello {contact.fName} {contact.lName}
</h1>
<p>{contact.email}</p>
<input name="fName" placeholder={contact.fName} />
<input name="lName" placeholder={contact.lName} />
<input name="email" placeholder={contact.email} />
<button onClick={handleClick}>Submit</button>
</div>
);
}
export default App;
I set initial state with empty string but I am trying to update input attributes with data from external source whenever user clicks submit button.
I heard I need to use useEffect method to api call in react, but I have no idea where to start.
if you're going to update the data on the button click, then you can use a count mechanism, a separate variable to keep track of the count.
const [count, setCount] = useState(0);
<button onClick={() => setCount(count + 1 )}>Submit</button>
async function handleClick() {
const res = await axios.get("url");
setContact(res.data);
}
useEffect(() => {
handleClick();
}, [contact, count]);

useState on array of input values removes focus

Im using the useState hook to update an array. This array renders a list of inputs.
This code does update the useState hook correctly but it removes focus from the input after every key press. Why is this happening and how can I fix it?
import React, { useState } from "react";
const Todos = () => {
const [todos, setTodos] = useState(["Read book", "Tidy room"]);
function update(index: number, event: React.ChangeEvent<HTMLInputElement>) {
const newTodos = [...todos];
newTodos[index] = event.target.value;
setTodos(newTodos);
}
return (
<ul>
{todos.map((item, index) => {
return (
<li key={item}>
<input
type="text"
value={item}
onChange={event => update(index, event)}
/>
</li>
);
})}
</ul>
);
};
export default Exercises;
So the problem is that you're using the item's value as the key for each <li>. When you change the value in the input, the key will change and react renders an entire new <li> instead of just changing the one that is already loaded on the screen.
The easiest solution would be to make each Todo an object, and give it a id that doesn't change:
import React, { useState } from "react";
interface Todo {
value: string;
id: string;
}
const Todos = () => {
const [todos, setTodos] = useState<Todo[]>([
{
value: "Read book",
id: '1'
},
{
value: "Tidy room",
id: '2'
}
]);
function update(index: number, event: React.ChangeEvent<HTMLInputElement>) {
const newTodos = [...todos];
newTodos[index].value = event.target.value;
setTodos(newTodos);
}
return (
<ul>
{todos.map((item, index) => {
return (
<li key={item.id}>
<input
type="text"
value={item.value}
onChange={event => update(index, event)}
/>
</li>
);
})}
</ul>
);
};
export default Exercises;

Using react-bootstrap in redux form

I am trying to integrate react-bootstrap Dropdown component in redux form. This is my code
import React from 'react'
import {Input,Form,FormGroup,FormControl,ControlLabel,Button,ButtonToolbar,Panel,Checkbox,Radio} from 'react-bootstrap'
import { reduxForm,Field,reset } from 'redux-form'
const FieldInput = ({ input, meta, type, placeholder, min, max }) => {
return (
<FormControl
type={type} onChange={input.onChange} />
)
}
class dropDown extends React.Component {
render() {
return (<FormControl componentClass="select" {...this.props} {...this.input} />)
}
}
let Gri = props => {
const { handleSubmit,pristine,submitting} = props
return (
<form onSubmit={handleSubmit}>
<div>
<FormGroup controlId="formInlineName">
<ControlLabel>User Name:</ControlLabel>
<Field name="firstname" component={FieldInput} type="text"/>
</FormGroup>
</div>
<div>
<FormGroup controlId="formControlsSelect">
<ControlLabel>Category:</ControlLabel>
<Field name="category_id" component={dropDown}>
<option value="1">Health</option>
<option value="2">Municipality Roads</option>
<option value="3">Women and Child Development</option>
</Field>
</FormGroup>
</div>
<Button bsStyle="success" type="submit" disabled={submitting}>SUBMIT</Button>
</form>
)
}
const onSubmit = values => {
console.log(values)
}
Gri= reduxForm({
form: 'gri',
onSubmit,
})(Gri)
export default Gri
In the output the dropdown list is shown but the value is not returned when I click submit. Please help me finding the solution

how to call handleSubmit from parent in redux-form

I have a problem I can't solve trying to use redux-form. I'm trying the Erikras boilerplate. I want the form to be a component and the parent to call handleSubmit (for the moment with a console.log just to confirm it works). Here, the two:
import React, {Component, PropTypes} from 'react';
import Helmet from 'react-helmet';
import {initialize} from 'redux-form';
import {connect} from 'react-redux';
import * as membersActions from 'redux/modules/members';
import {isLoaded, loadMembers} from 'redux/modules/members';
import { DashboardList } from 'components';
import { DashboardHeader } from 'components';
import { DashboardAdding } from 'components';
import { asyncConnect } from 'redux-async-connect';
#asyncConnect([{
deferred: true,
promise: ({store: {dispatch, getState}}) => {
if (!isLoaded(getState())) {
return dispatch(loadMembers());
}
}
}])
#connect(
state => ({
members: state.members.data,
error: state.members.error,
loading: state.members.loading
}),
{...membersActions, initialize })
export default class Dashboard extends Component {
static propTypes = {
initialize: PropTypes.func.isRequired,
members: PropTypes.array,
loadMembers: PropTypes.func.isRequired
}
handleSubmit = (data) => {
console.log(data);
this.props.initialize('dashAdding', {});
}
handleInitialize = () => {
this.props.initialize('dashAdding', {
pseudo: 'Pibo',
email: 'pibirino#gmail.com'
});
}
render() {
const {members} = this.props;
return (
<div className="container">
<h1>Dashboard</h1>
<Helmet title="Dashboard"/>
<DashboardHeader />
<div>
<DashboardList members={members}/>
<h3>Ici commence le form</h3>
<div style={{textAlign: 'center', margin: 15}}>
<button className="btn btn-primary" onClick={this.handleInitialize}>
<i className="fa fa-pencil"/> Initialize Form
</button>
</div>
</div>
<DashboardAdding onSubmit={this.handleSubmit}/>
<p>Bleeeeah!!</p>
</div>
);
}
}
and here the child:
import React, {Component, PropTypes} from 'react';
import {reduxForm} from 'redux-form';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import memberValidation from './memberValidation';
#reduxForm({
form: 'dashAdding',
fields: ['pseudo', 'email'],
validate: memberValidation
})
export default class DashboardAdding extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
handleSubmit: PropTypes.func.isRequired,
resetForm: PropTypes.func.isRequired
}
render() {
const {
fields: { pseudo, email},
handleSubmit,
resetForm
} = this.props;
const renderInput = (field, label) =>
<div className={'form-group' + (field.error && field.touched ? ' has-error' : '')}>
<label htmlFor={field.name} className="col-sm-2">{label}</label>
<div className={'col-sm-8 '}>
<input type="text" className="form-control" id={field.name} {...field}/>
</div>
</div>;
return (
<div>
<form className="form-horizontal" onSubmit={handleSubmit}>
{renderInput(pseudo, 'Full Name')}
{renderInput(email, 'Email', true)}
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button className="btn btn-success" onClick={handleSubmit}>
<i className="fa fa-paper-plane"/> Submit
</button>
<button className="btn btn-warning" onClick={resetForm} style={{marginLeft: 15}}>
<i className="fa fa-undo"/> Reset
</button>
</div>
</div>
</form>
</div>
);
}
}
So... it doesn't work I think I'm missing some important knowledge. I thought that the reason is because the form component is dumb, and it doesn't have the dispatch function. So, I tryed to add this (several times in several different ways) importing the action creator from the specific folder:
#connect(() => ({}),
dispatch => actionCreators( dispatch)
)
But I don't still get what I want. What's the problem?
So, finally I found the answer by myself. In fact, I decided to not use #connect, whitch is deprecated (despite it's still used in the boilerplate) and to use connect, as in the example of the redux-form documentation. The only change concerned the parent, but I'll post them both in case I missed something. The following code works good.
Here is the code:
import React, {Component, PropTypes} from 'react';
import Helmet from 'react-helmet';
import {initialize} from 'redux-form';
import {connect} from 'react-redux';
import * as membersActions from 'redux/modules/members';
import {isLoaded, loadMembers} from 'redux/modules/members';
import { DashboardList } from 'components';
import { DashboardHeader } from 'components';
import { DashboardAdding } from 'components';
import { asyncConnect } from 'redux-async-connect';
#asyncConnect([{
deferred: true,
promise: ({store: {dispatch, getState}}) => {
if (!isLoaded(getState())) {
return dispatch(loadMembers());
}
}
}])
class Dashboard extends Component {
static propTypes = {
members: PropTypes.array,
error: PropTypes.string,
loading: PropTypes.bool,
addMember: PropTypes.func,
initialize: PropTypes.func.isRequired,
newMemberData: PropTypes.object
}
handleSubmit = (data, dispatch) => {
dispatch(addMember(JSON.stringify(data)));
this.props.initialize('dashboardForm', {});
}
handleInitialize = () => {
this.props.initialize('dashboardForm', {
pseudo: 'Pibo',
email: 'pibirino#gmail.com'
});
}
render() {
const {members} = this.props;
return (
<div className="container">
<h1>Dashboard</h1>
<Helmet title="Dashboard"/>
<DashboardHeader />
<div>
<DashboardList members={members}/>
<h3>Ici commence le form</h3>
<div style={{textAlign: 'center', margin: 15}}>
<button className="btn btn-primary" onClick={this.handleInitialize}>
<i className="fa fa-pencil"/> Initialize Form
</button>
</div>
</div>
<DashboardAdding onSubmit={this.handleSubmit}/>
</div>
);
}
}
function mapStateToProps(state) {
return {
members: state.members.data,
error: state.members.error,
loading: state.members.loading,
newMemberData: state.addSingleMember.data
};
}
function matchDispatchToProps(dispatch) {
return bindActionCreators({
addActions,
initialize: initialize
}, dispatch);
}
export default connect(mapStateToProps, matchDispatchToProps)(Dashboard);
...and the child component:
import React, {Component, PropTypes} from 'react';
import {reduxForm} from 'redux-form';
import memberValidation from './memberValidation';
class DashboardAdding extends Component {
static propTypes = {
fields: PropTypes.object.isRequired,
handleSubmit: PropTypes.func.isRequired,
resetForm: PropTypes.func.isRequired
}
render() {
const {
fields: { pseudo, email},
handleSubmit,
resetForm
} = this.props;
const renderInput = (field, label) =>
<div className={'form-group' + (field.error && field.touched ? ' has-error' : '')}>
<label htmlFor={field.name} className="col-sm-2">{label}</label>
<div className={'col-sm-8 '}>
<input type="text" className="form-control" id={field.name} {...field}/>
{field.error && field.touched && <div className="text-danger">{field.error}</div>}
</div>
</div>;
return (
<div>
<form className="form-horizontal" onSubmit={handleSubmit.bind(this)}>
{renderInput(pseudo, 'Pseudo')}
{renderInput(email, 'Email', true)}
<div className="form-group">
<div className="col-sm-offset-2 col-sm-10">
<button className="btn btn-success" onClick={handleSubmit}>
<i className="fa fa-paper-plane"/> Submit
</button>
<button className="btn btn-warning" onClick={resetForm} style={{marginLeft: 15}}>
<i className="fa fa-undo"/> Reset
</button>
</div>
</div>
</form>
</div>
);
}
}
export default reduxForm({
form: 'dashboardForm',
fields: ['pseudo', 'email'],
validate: memberValidation,
asyncBlurFields: ['email']
})(DashboardAdding);
The addMember function contains obviously a promise.
I hope it will helps somebody :-)

Resources