Input doesn't work in Mobx Store at Reactjs - reactjs

At first, I made 'Store' like below.
I want to put input in login state on realtime.
import { observable, action } from 'mobx'
export default class SingUpIn {
#observable initialState = {
register: {
email: '',
username: '',
password: '',
passwordConfirm: ''
},
login: {
email: '',
password: ''
}
}
#action changeLogin = (name, value) => {
this.initialState.login.name = value
}
}
And I injected this inside one component.
But when I write something on Input, any input is not being appeard
Could you recommend some solution?
import React, { Component } from 'react'
import { Link } from 'react-router-dom'
import { observer, inject } from 'mobx-react'
#inject('SignUpIn')
#observer
class SignUp extends Component {
handleChange = e => {
const { SignUpIn } = this.props
SignUpIn.changeLogin(e.target.name, e.target.value)
}
render () {
const { SignUpIn } = this.props
return (
<div>
<input
id="email"
name="email"
placeholder="email"
value={SignUpIn.initialState.login.email}
onChange={this.handleChange}
/>
</div>
)
}
}
export default SignUp

try to use this
#action changeLogin = (name, value) => {
this.initialState.login[name]= value
}

Just to remind the reason about kkangil solution:-
When you are using (.) notation to access the object property, it will look for string value of the property name.
this.initialState.login.name : This will just look for the string value of name in the object.
Where as using the bracket notation [], the property identifiers have to be string or a variable that
references the string.
So, you can use name which is a variable that is referencing another string.
eg
var obj = {
charmandar: 'fire',
squirtle: 'water'
}
var charmandar = 'squirtle'
console.log(obj.charmandar); // fire
console.log(obj[charmandar]); // water

Related

React Speech Recognition - inserting the text to the memory by updating the state

There is a similar question but I can't comment on it so I opening a new one.
I am new to React and try to implement React SpeechRecognition component for my app. The text should be in an input box. the code for it (from react doc [https://www.npmjs.com/package/react-speech-recognition][1] - with span tag instead of an input):
import React, { PropTypes, Component } from 'react'
import SpeechRecognition from 'react-speech-recognition'
const propTypes = {
// Props injected by SpeechRecognition
transcript: PropTypes.string,
resetTranscript: PropTypes.func,
browserSupportsSpeechRecognition: PropTypes.bool
}
class Dictaphone extends Component {
render() {
const { transcript, resetTranscript, browserSupportsSpeechRecognition } = this.props
if (!browserSupportsSpeechRecognition) {
return null
}
return (
<div>
<button onClick={resetTranscript}>Reset</button>
<span>{transcript}</span>
</div>
)
}
}
Dictaphone.propTypes = propTypes
export default SpeechRecognition(Dictaphone)
Now I try to update a state of text (a string) by the transcript (the words that have been already recognized) but I can't make it.
from an earlier question, someone suggested this:
<input
type="text"
value={transcript}
onChange={event => this.onInputChange(event.target.value)}
/>
now when I speak, I do see the words in the input box,
so the final code should be :
import React, { Component } from "react";
import PropTypes from "prop-types";
import SpeechRecognition from "react-speech-recognition";
const propTypes = {
// Props injected by SpeechRecognition
transcript: PropTypes.string,
resetTranscript: PropTypes.func,
browserSupportsSpeechRecognition: PropTypes.bool
};
class Dictaphone extends Component {
constructor() {
super();
this.state = {
text: '',
events: []
}
}
onInputChange = (event) => {
console.log (event.target.value);
this.setState( {text: event.target.value} );
}
render() {
const { transcript, resetTranscript, browserSupportsSpeechRecognition } = this.props;
if (!browserSupportsSpeechRecognition) {
return null
}
return (
<div>
<button onClick={resetTranscript}>Reset</button>
<input
className='bg-light-blue'
type="text"
value={transcript}
onChange={event => this.onInputChange(event.target.value)}
/>
</div>
)
}
}
Dictaphone.propTypes = propTypes;
export default SpeechRecognition(Dictaphone);
but when I console.log(event.target.value) which is text - I see nothing so I'm doing something wrong.
Note that if I just write in the render func:
render() {
const { transcript, resetTranscript, browserSupportsSpeechRecognition } = this.props;
var x = transcript;
console.log('x is ',x);
console.log('x length is: ',x.length);
.....
it does console the transcript (x) but it's not what I want - I need to save it in text by updating the state.
any suggestion?
If you need to store the transcript prop in your state you should do something like this.
componentDidUpdate(prevProps){
if(prevProps.transcript !== this.props.transcript){
this.setState({
text: this.props.transcript
});
}
}
In your render method use this.state.text to show in the input value.
Also in your constructor do
this.state = {
text: props.transcript
}

How to manage state in a signup flow (ReactJS)

So, I'm building a signup and payment flow using React/NextJS, AWS Cognito, and Stripe. I have created a class component to manage state and the overall flow with child components handling the individual steps. The problem I am having is managing the state so that each component can access the state and make changes to it as well as use functions that are in the parent component and not within the child components. Keep note that the child components are functional and not classes. Here is the flow step by step:
Parent Component
import React, { Component } from "react";
import Layout from "../../components/layouts/mainlayout/mainlayout";
//import { handleSubmit } from "../../components/auth/awshelper";
import { Auth } from "aws-amplify";
import FlowStep1 from "../../components/auth/clubflow/step1";
import FlowStep2 from "../../components/auth/clubflow/step2";
import FlowStep3 from "../../components/auth/clubflow/step3";
//import { Router } from "next/router";
const meta = {
title: "Join the club!",
description: "Sign up and enjoy the best travel experiences ever."
};
class ClubFlow extends Component {
state = {
firstname: "",
lastname: "",
username: "",
phonenumber: "",
password: "",
confirmpassword: "",
step: 1,
go: false,
plan: null,
member: false,
errors: {
cognito: null,
blankfield: false,
passwordmatch: false
}
};
/*Unnecessary functions:
getStripeFunc = func => {
return func;
};
*/
clearErrorState = () => {
this.setState({
errors: {
cognito: null,
blankfield: false,
passwordmatch: false
}
});
};
choosePlan = e => {
setState({ plan: e.target.value });
};
onInputChange = event => {
//const [firstname, setFirstname] = useState("");
this.setState({
[event.target.id]: event.target.value
});
document.getElementById(event.target.id).classList.remove("is-danger");
};
handleSubmit = async event => {
event.preventDefault();
// Form validation
this.clearErrorState();
const error = null; /*Validate(event, this.state)*/
if (error) {
console.log("an validation erreor was fired");
this.setState({
errors: { ...this.state.errors, ...error }
});
}
// AWS Cognito integration here
const { firstname, lastname, phonenumber, username, password } = this.state;
try {
const signUpResponse = await Auth.signUp({
username,
password,
attributes: {
name: firstname,
family_name: lastname,
phone_number: phonenumber
}
});
if (signUpResponse) {
this.setState({ step: 2, go: true });
}
} catch (error) {
let err = null;
!error.message ? (err = { message: error }) : (err = error);
this.setState({
errors: { ...this.state.errors, cognito: error }
});
}
};
//This function sets which plan the user selects. Eventually this value will be passed down to the checkout form as a prop.
goNext = async () => {
try {
if (this.state.step === 1) {
this.handleSubmit(event);
if (
this.state.step <
3 /*&&
this
.signUpResponse /*Remove the previous comment in order for the next button to work correctly.*/
) {
this.setState(state => ({
step: state.step + 1
}));
}
} else if (this.state.step === 2) {
this.setState(state => ({
step: state.step + 1
}));
} else {
this.getStripeFunc();
}
} catch (error) {
console.log("You have a problem");
}
};
goBack = () => {
if (this.state.step > 1) {
this.setState(state => ({
step: state.step - 1
}));
}
};
render() {
let stage;
if (this.state.step === 1) {
stage = (
<FlowStep1 state={this.state} onInputChange={this.onInputChange} />
);
} else if (this.state.step === 2) {
stage = <FlowStep2 state={this.state} choosePlan={this.choosePlan} />;
} else {
stage = <FlowStep3 state={this.state} />;
}
//console.log(this.state.plan);
return (
<Layout class={"ovh"} meta={meta}>
A user is able to signup and creates an account by entering their name, email, phone, and password.
import FormErrors from "../FormErrors";
import { Auth } from "aws-amplify";
import React, { Component } from "react";
/*import {
backspacerUP,
backspacerDOWN
} from "../../utilities/phonenumbervalidator";
const onKeyUp = backspacerUP;
const onKeyDown = backspacerDOWN;
Might need to use a plugin: https://www.npmjs.com/package/react-phone-input-auto-format*/
class FlowStep1 extends Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
return (
<section className="section auth">
<div className="container">
<h1>Register</h1>
<FormErrors /*formerrors={state.errors}*/ />
A user is able to choose a plan which needs to pass the plan that the user chooses onto step 3:
import React, { useState } from "react";
const FlowStep2 = (props) => {
const plan
const [plan, setPlan] = useState(0);
return (
<div className="mb-4">
<h2>this is what is in state:{plan}</h2>
<input
type="radio"
name="plan"
value="1"
readOnly
//checked={this.state.plan === 1}
onChange={() => setPlan(1)}
/>
<input
type="radio"
name="plan"
value="2"
readOnly
onChange={() => setPlan(2)}
className="ml-3"
/>
<input
type="radio"
name="plan"
value="3"
//checked={true}
onChange={() => setPlan(3)}
className="ml-3"
/>
</div>
);
};
export default FlowStep2;
A user is able to enter their credit card info and submit it. Once the charge is okay'd by stripe and charged based on the plan the user choosed in step two they will get a confirmation email and will be navigated to the welcome page. The selected plan will need to be eventually passed on to an express server that will handle the charge and pass it on to stripe for processing charging based on what plan they selected.
import ClubPayWrap from "../../payments/clubpaywrap";
const FlowStep3 = props => {
return (
<div>
<h2>Payment</h2>
<ClubPayWrap flowstate={props.state} />
</div>
);
};
export default FlowStep3;
Please, let me know if I need to give more detail.
For managing states in react based application there are different approaches. You need to store the logged in user data in a global store in which you can access in different routes and components.
The most used store manager to react is Redux.In the latest version, it provided some hooks. The redux hooks made it so easy to access to your store.
The next one is mobX. I personally haven't used it yet and I can not help you with that!
The other one is Context Api which is provided by react itself. React added some hooks to make it easy to use.
There is another technology provided for managing states in React called Rxjs which is a little bit different and maybe is not good for your case.
In the end I think number one is the perfect solution for you and then number 3.

React unable to set two way binding

Here are my two components. I just need to update my state in the login component. I am not sure what I am doing wrong here. I am trying to pass the data on change to the login component. The data is getting captured in e.target.value for each character, but then it resets the state.
I have tried to move the userObj inside the state as well,but does not work
import React, { Component } from 'react';
import FormHeader from './FormHeader'
class NonLoggenInForm extends Component {
render() {
return (
<div className="marginTop1 formPanel">
<FormHeader label={this.props.label}/>
{this.props.content.map((key)=>{
return <input type={key.type}
value = {key.value}
placeholder = {key.name}
required = {key.required}
onChange = {e=>this.props.onChange(e)}
className = "formInput"
name = {key.name}
key = {key.id}
/>;
})}
<button onClick={this.props.onSubmit}> Sign in</button>
</div>
);
}
}
export default NonLoggenInForm;
import React, { Component } from 'react';
import Logo from '../shared/Logo';
import NonLoggenInForm from '../shared/NonLoggenInForm';
class Login extends Component {
changeHandler = (e) => {
console.log(e.target.value);
this.setState({
[e.target.name] : e.target.value
});
}
loginHandler = (e) => {
e.preventDefault();
console.log(this.state);
}
render() {
let userObj = [
{
name : 'userId',
type: 'text',
required: true,
value : '',
id : 1
},
{
name : 'password',
type : 'password',
required : true,
value : '',
id : 2
}
];
return (
<div className="nonLoggedInPages">
<Logo/>
<NonLoggenInForm content={userObj} label="Sign in" onSubmit={this.loginHandler} onChange={this.changeHandler}/>
</div>
);
}
}
export default Login;
Moved the user Obj to state again and changed the onChange function as below
changeHandler = (e) => {
let objIndex = this.state.userObj.findIndex((ele)=>{
return ele.name === e.target.name;
});
let upadtedObject = [...this.state.userObj];
upadtedObject[objIndex].value = e.target.value;
this.setState({
userObj : upadtedObject
});
e.target.value = this.state.userObj[objIndex].value;
}

Accept multiple input field in redux?

I'm learning redux and can able to update single input field but when there's more than 1 input field can't able to update state of both input field!
Here's my code please check it.
My main index.js:
import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import {FormReducer} from "./reducers/name";
import { createStore } from "redux";
import { Provider } from "react-redux";
const store = createStore(FormReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById("root")
);
My presentational and input field component:
import React, { Component } from "react";
import { connect } from "react-redux";
import { bindActionCreators } from "redux";
import * as actions from "./actions";
class App extends Component {
inputData = event => {
this.props.actions.addToDo({ name: event.target.value });
};
submitData = event => {
console.log(this.props.name);
// console.log(this.props.mobile);
event.preventDefault();
}
render() {
return (
<div>
<form onSubmit={this.submitData}>
FirstName:
<input
type="text"
name={this.props.name}
onChange={this.inputData}
/>
<input
type="text"
name={this.props.mobile}
onChange={this.inputData2}
/>
<button type="submit">Submit</button>
</form>
{this.props.name}
{this.props.mobile}
</div>
);
}
}
const mapStateToProps = state => ({
mobile: state.mobile,
name: state.name
});
const mapDispatchToProps = dispatch => {
return {
actions: bindActionCreators(actions, dispatch)
};
};
export default connect(mapStateToProps, mapDispatchToProps)(App);
In my presentational component I want to make input acceptance such like array like [event.target.name]:event.target.value or something like this.
But when I try to do this with redux it's not working properly. Please check my code and give your input!
My reducer function:
let init = {
name: ''
}
export const FormReducer = (state = init, action) => {
switch (action.type) {
case "ADD_NAME":
return {...state, name:action.name, mobile:action.mobile}
default:
return state;
}
};
My action function which takes action on new input:
let init = {
name: ''
}
export const FormReducer = (state = init, action) => {
switch (action.type) {
case "ADD_NAME":
return {...state, name:action.name, mobile:action.mobile}
default:
return state;
}
};
And also as you can see I want to print both name and mobile both but it's only printing on which I'm working. Please give code so that I can able to print both simultaneously.
Thanks in advance!
It should be like this.
Use ecma6#computed property name [event.target.name]
inputData = event => {
this.props.actions.addToDo({ [event.target.name]: event.target.value });
};
EDIT :
in reducers,add this .
let init = {
name: { key : "name", value : "" },
mobile: { key: "mobile", value: "" },
};
reducer :
case "ADD_NAME":
console.log(action,state);
return {
...state,
name: {
...state.name, value: action.name||state.name.value
},
mobile: {
...state.mobile,
value: action.mobile || state.mobile.value
}
};
If you checked in render,both input field need name attribute which is not initialised and coming blank via props mapped in mapStateToProps.
So,you are not getting name attribute in event handler.
Need to initilise it.I assumed mobile and name.
1rst make state and save field inputs there like this.
state = {
username: "",
password: ""
}
where updateValue will save values from inputs to state
updateValue = (e) => {
this.setState({ [e.target.name]: e.target.value });
}
<input type="text" name="username" value={this.state.username} onChange={(e) => this.updateValue(e)} />
<input type="password" name="password" value={this.state.password} onChange={(e) => this.updateValue(e)} />
then you can collect data from state and pass it to your function, for example like this login form.
submitData = event => {
const user = {
username: this.state.username,
password: this.state.password
}
// now pass this `user` to your action
event.preventDefault();
}

Property not found in props of React element `form`

Hi i'm having problems with Flow and React.
I'm getting these errors and I want to get rid of them. What am I missing I have search everywhere. I understand that the props are missing but I can't seem to find where to define them.
Flow: property className. Property not found in props of React element form
Flow: property onSubmit. Property not found in props of React element form
export default class LoginForm extends React.Component {
_submitForm: Function;
constructor(props?: {}) {
super(props);
this.state = {
form: {
email: '',
password: '',
},
errors: {
_form: "",
email: "",
password: ""
}
};
this._submitForm = this._submitForm.bind(this);
}
_handleValues(param: string, value?: string) {
let obj = this.state;
obj['form'][param] = value;
this.setState(obj);
}
_submitForm(event: Event) {
this._clearErrors(event);
let form = this.state.form;
AxiosQueue
.post({
url: LINK.AUTHENTICATE,
data: form
})
.then(({data}) => {
if (!data.success) {
return;
}
})
.catch((response) => {
console.error(response);
});
}
render() {
const {errors, form} = this.state;
const user = UserStore.getUser();
const formText = FORM_TEXT[user.language || "en_AU"];
return (
<form className="form-inline" onSubmit={this._submitForm}>
{errors._form}
<InputEmail id="email" error={errors.email} value={form.email} callback={this._handleValues}/>
<InputPassword id="password" error={errors.password} value={form.password}
callback={this._handleValues}/>
<button type="submit" className="btn btn-default">{formText.LOGIN}</button>
</form>
);
}
}
There is conflict with your variable name form in Syntex const {errors, form} = this.state; and form component. Solution is to give some other name in this.state. Like
this.state = {
formValidation:{
//Validation properties
}
}
And consume so that will remove conflict
const {formValidation} = this.state

Resources