React state hook issue - javascript

I'm trying to use the state hook to make the onChange work properly with material-ui to handle the error texts. But getting one issue. I have attached the screen of the error coming in the console.
Here's my code:
import React, { Component, useState } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
export const CreateForm = (props) => {
const { containerClass } = props;
let [dataAction, setDataAction] = useState({ errorNameText: 'Enter product name!' });
let errorNameText = 'Enter the name!';
const handleNameChange = (event) => {
const name = event.target.value;
if(name && name !== '') {
setDataAction(prevState => {
prevState.errorNameText = '';
})
}
}
return(
<div className={containerClass}>
<div>
<TextField
className="product_nameField"
floatingLabelText="Product Name"
errorText={dataAction.errorNameText}
onChange={handleNameChange}
/>
</div>
<br/>
<div>
<TextField
className="product_priceField"
floatingLabelText="Product Price"
/>
</div>
<br/>
<div>
<TextField
className="product_infoField"
floatingLabelText="Product Info"
/>
</div>
<br/>
<div>
<RaisedButton label="Submit" primary={true} />
</div>
</div>
);
}
I guess I'm missing something vital over here on making use of the state hook in the proper way.
Any help would be appreciated.

You are setting your state in a wrong way. Two issues here:
setDataAction(prevState => {
prevState.errorNameText = '';
});
For an arrow function if you want to return an object implicitly, you need to wrap it with ()
You are mutating your state. Do not set it like prevState.errorNameText = ''
Here is the right way:
setDataAction(prevState => ({
...prevState,
errorNameText: '';
}));
So, you should spread the current state and make the necessary changes. In your case, you don't have any other properties but this is the right way. Because, if you add another property to your state in the future and do not use spread syntax here, you'll lose all other properties in your state.

change
const handleNameChange = (event) => {
const name = event.target.value;
if(name && name !== '') {
setDataAction(prevState => {
prevState.errorNameText = '';
})
}
}
to
const handleNameChange = (event) => {
const name = event.target.value;
if(name && name !== '') {
setDataAction({ errorNameText: ''}) <------ CHANGED
}
}
Please let me know if it solved it then I will elaborate.

The setDataAction will set the value of the state to the value passed or the returned value if you pass a function
You function just mutates the previous state and then returns nothing. So the next render the dataAction will be undefined and you will try to do dataAction.errorNameText and crash.
Use
// no point to use this syntax since the new state
// does not depend on the previous state
setDataAction(prevState => ({
errorNameText: '';
}))
or
// use this syntax for your use case
setDataAction({
errorNameText: '';
})

Related

How to render the next component in React?

I have three components First, Second and Third that need to render one after the other.
My App looks like this at the moment:
function App() {
return (
<First/>
)
}
So ideally, there's a form inside First that on submission (onSubmit probably) triggers rendering the Second component, essentially getting replaced in the DOM. The Second after some logic triggers rendering the Third component and also passes a value down to it. I'm not sure how to go on about it.
I tried using the useState hook to set a boolean state to render one of the first two components but I would need to render First, then somehow from within it change the set state in the parent which then checks the boolean and renders the second. Not sure how to do that. Something like below?
function App() {
const { isReady, setIsReady } = useState(false);
return (
isReady
? <First/> //inside this I need the state to change on form submit and propagate back up to the parent which checks the state value and renders the second?
: <Second/>
);
}
I'm mostly sure this isn't the right way to do it.
Also need to figure out how to pass the value onto another component at the time of rendering it and getting replaced in the DOM. So how does one render multiple components one after the other on interaction inside each? A button click for example?
Would greatly appreciate some guidance for this.
then somehow from within it change the set state in the parent which then checks the boolean and renders the second.
You're actually on the right track.
In React, when you're talking about UI changes, you have to manage some state.
So we got that part out of the way.
Now, what we can do in this case is manage said state in the parent component and pass functions to the children components as props in-order to allow them to control the relevant UI changes.
Example:
function App() {
const { state, setState } = useState({
isFirstVisible: true,
isSecondVisible: false,
isThirdVisible: false,
});
const onToggleSecondComponent = (status) => {
setState(prevState => ({
...prevState,
isSecondVisible: status
}))
}
const onToggleThirdComponent = (status) => {
setState(prevState => ({
...prevState,
isThirdVisible: status
}))
}
return (
{state.isFirstVisible && <First onToggleSecondComponent={onToggleSecondComponent} /> }
{state.isSecondVisible && <Second onToggleThirdComponent={onToggleThirdComponent} /> }
{state.isThirdVisible && <Third/> }
);
}
Then you can use the props in the child components.
Example usage:
function First({ onToggleSecondComponent }) {
return (
<form onSubmit={onToggleSecondComponent}
...
</form
)
}
Note that there are other ways to pass these arguments.
For example, you can have one function in the parent comp that handles them all, or you can just pass setState to the children and have them do the logic.
Either way, that's a solid way of achieving your desired outcome.
Seen as your saying there are stages, rather than having a state for each stage, just have a state for the current stage, you can then just increment the stage state to move onto the next form.
Below is a simple example, I've also used a useRef to handle parent / child state, basically just pass the state to the children and the children can update the state. On the final submit I'm just JSON.stringify the state for debug..
const FormContext = React.createContext();
const useForm = () => React.useContext(FormContext);
function FormStage1({state}) {
const [name, setName] = React.useState('');
state.name = name;
return <div>
Stage1:<br/>
name: <input value={name} onChange={e => setName(e.target.value)}/>
</div>
}
function FormStage2({state}) {
const [address, setAddress] = React.useState('');
state.address = address;
return <div>
Stage2:<br/>
address: <input value={address} onChange={e => setAddress(e.target.value)}/>
</div>
}
function FormStage3({state}) {
const [hobbies, setHobbies] = React.useState('');
state.hobbies = hobbies;
return <div>
Stage3:<br/>
hobbies: <input value={hobbies} onChange={e => setHobbies(e.target.value)}/>
</div>
}
function Form() {
const [stage, setStage] = React.useState(1);
const state = React.useRef({}).current;
let Stage;
if (stage === 1) Stage = FormStage1
else if (stage === 2) Stage = FormStage2
else if (stage === 3) Stage = FormStage3
else Stage = null;
return <form onSubmit={e => {
e.preventDefault();
setStage(s => s + 1);
}}>
{Stage
? <React.Fragment>
<Stage state={state}/>
<div>
<button>Submit</button>
</div>
</React.Fragment>
: <div>
{JSON.stringify(state)}
</div>
}
</form>
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<Form/>);
<script crossorigin src="https://unpkg.com/react#18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#18/umd/react-dom.development.js"></script>
<div id="root"></div>

Visit each child in props.children and trigger a function

I want to be able to visit the children <Textfield> of my form <Form> upon submit.
In each child hook object, I also want to trigger a certain function (eg., validate_field). Not sure if this possible in hooks? I do not want to use ref/useRef and forwardRef is a blurred concept to me yet (if that's of any help).
My scenario is the form has been submitted while the user did not touch/update any of the textfields so no errors were collected yet. Upon form submit, I want each child to validate itself based on certain constraints.
I tried looking at useImperativeHandle too but looks like this will not work on props.children?
Updated working code in:
https://stackblitz.com/edit/react-ts-jfbetn
submit_form(evt){
props.children.map(child=>{
// hypothetical method i would like to trigger.
// this is what i want to achieve
child.validate_field() // this will return "is not a function" error
})
}
<Form onSubmit={(e)=>submit_form(e)}
<Textfield validations={['email']}>
<Textfield />
<Textfield />
</Form>
Form.js
function submit_form(event){
event.preventDefault();
if(props.onSubmit){
props.onSubmit()
}
}
export default function Form(props){
return (
<form onSubmit={(e)=>submit_form(e)}>
{props.children}
</form>
)
}
So the Textfield would look like this
…
const [value, setValue] = useState(null);
const [errors, setErrors) = useState([]);
function validate_field(){
let errors = []; // reset the error list
props.validations.map(validation => {
if(validation === 'email'){
if(!some_email_format_validator(value)){
errors.push('Invalid email format')
}
}
// other validations (eg., length, allowed characters, etc)
})
setErrors(errors)
}
export default function Textfield(props){
render (
<input onChange={(evt)=>setValue(evt.target.value)} />
{
errors.length > 0
? errors.map(error => {
return (
<span style={{color:'red'}}>{error}</span>
)
})
: null
}
)
}
I would recommend moving your validation logic up to the Form component and making your inputs controlled. This way you can manage the form state in the parent of the input fields and passing in their values and onChange function by mapping over your children with React.cloneElement.
I don't believe what you're trying to do will work because you are trying to map over the children prop which is not the same as mapping over say an array of instantiated child elements. That is to say they don't have state, so calling any method on them wouldn't be able to give you what you wanted.
You could use a complicated system of refs to keep the state in your child input elements, but I really don't recommend doing that as it would get hairy very fast and you can just solve the issue by moving state up to the parent.
simplified code with parent state:
const Form = ({ children }) => {
const [formState, setFormState] = useState(children.reduce((prev, curr) => ({ ...prev, [curr.inputId]: '' }), {}));
const validate = (inputValue, validator) => {}
const onSubmit = () => {
Object.entries(formState).forEach(([inputId, inputValue]) => {
validate(
inputValue,
children.filter(c => c.inputId === inputId)[0].validator
)
})
}
const setFieldValue = (value, inputId) => {
setFormState({ ...formState, [inputId]: value });
};
const childrenWithValues = children.map((child) =>
React.cloneElement(child, {
value: formState[child.inputId],
onChange: (e) => {
setFieldValue(e.target.value, child.inputId);
},
}),
);
return (
<form onSubmit={onSubmit}>
{...childrenWithValues}
</form>
)
};
const App = () =>
<Form>
<MyInput validator="email" inputId="foo"/>
<MyInput validator="email" inputId="foo"/>
<MyInput validator="password" inputId="foo"/>
</Form>
I still don't love passing in the validator as a prop to the child, as pulling that out of filtered children is kinda jank. Might want to consider some sort of state management or pre-determined input list.

Nested object stored as state variable deleting newer values when older values are modified

I have a react component which passes user input value to a props function. The parent function just appends those inputs to an object. However, when an older value is modified, all the newer values are removed. Please refer to the screenshots.
This is the parent. ExamArea.js
import McqQuestion from './McqQuestion'
import React, { useState, useEffect } from 'react';
import './ExamArea.css'
function ExamArea(props) {
const[currentQuesID, setCurrentQuesID] = useState(2);
const[mcqQuestionList, setmcqQuestionList] = useState([<McqQuestion returnfunc={returnFromMcqQuestion} id={1}/>]);
const[ques, setQues] = useState({});
function returnFromMcqQuestion(quesID, thisQuestion) {
var temp = {...ques};
temp["ques"+quesID] = thisQuestion;
console.log(temp);
setQues(temp);
}
function generateMCQ(questionid) {
return (<McqQuestion returnfunc={returnFromMcqQuestion} id={questionid}/>)
}
function addAnotherQuestion() {
setmcqQuestionList(mcqQuestionList.concat(generateMCQ(currentQuesID)));
setCurrentQuesID(currentQuesID+1);
}
return (
<div className="ExamArea">
{mcqQuestionList}
<button onClick={()=>addAnotherQuestion()} class="add_another_question_button">+ Add Another Question</button>
</div>
);
}
export default ExamArea;
This is the child.
import './McqQuestion.css'
import React, { useState, useEffect } from 'react';
import { Paper, TextField } from '#material-ui/core';
import InputBase from '#material-ui/core/InputBase';
/*
This is the component that lets the maker create the question, and then stores the question to packedQuestion.
packedQuestipn is in a format which can be directly sent to the API to be uploaded to the database.
A basic question has question_text, question.title
Props passed:
props.id = The Question ID.
props.returnfunc = The function that gets called with packedQuestion and props.id when everything is done.
props.returnfunc(props.id, packedQuestion) is the thing that is called.
*/
function McqQuestion(props) {
const [packedQuestion, setPackedQuestion] = useState({});
useEffect(()=> props.returnfunc(props.id, packedQuestion));
/*These two variables store a local copy of packedQuestion. These variables are first updated with the information from
onChange (or a variation of it), and then packedQuestion is set to an instance of this. */
let local_question_mcq = {};
let local_answerChoices_mcq = {};
function fillUpQuestionWithDefault(){
function addOption(character, value) {
local_answerChoices_mcq[character] = value;
local_question_mcq["answer_choices"] = local_answerChoices_mcq;
}
function addQuestion(title, value){
if(title){
local_question_mcq['title'] = value;
}
else {
local_question_mcq['question_text'] = value;
}
}
addQuestion(true, "Question "+props.id);
addQuestion(false, "");
addOption("a", "");
addOption("b", "");
addOption("c", "");
addOption("d", "");
local_question_mcq['title'] = "Question " + props.id;
local_question_mcq['id'] = props.id;
setPackedQuestion(local_question_mcq);
}
useEffect(() =>fillUpQuestionWithDefault(), []);
function optionOnInputFunc(character, value) {
local_question_mcq = {...packedQuestion};
local_answerChoices_mcq = {...local_question_mcq["answer_choices"]};
local_answerChoices_mcq[character] = value;
local_question_mcq["answer_choices"] = local_answerChoices_mcq;
setPackedQuestion(local_question_mcq);
}
function questionOnInputFunc(title, value) {
if(title){
local_question_mcq = {...packedQuestion};
local_question_mcq['title'] = value;
setPackedQuestion(local_question_mcq);
}
else {
local_question_mcq = {...packedQuestion};
local_question_mcq['question_text'] = value;
setPackedQuestion(local_question_mcq);
}
}
function mcqChoiceGeneratingFunc() {
return (
<div class = "Opt">
<TextField onChange = {e => optionOnInputFunc('a', e.target.value)} label="Option A" variant="filled" multiline rowsMax={4}/>
<TextField onChange = {e => optionOnInputFunc('b', e.target.value)} label="Option B" variant="filled" multiline rowsMax={4}/>
<TextField onChange = {e => optionOnInputFunc('c', e.target.value)} label="Option C" variant="filled" multiline rowsMax={4}/>
<TextField onChange = {e => optionOnInputFunc('d', e.target.value)} label="Option D" variant="filled" multiline rowsMax={4}/>
</div>
);
}
return (
<Paper class="Question">
<form class="Question-form">
<a class = "editpencil">✎</a>
<InputBase class = "questionedit"
onChange = {e => questionOnInputFunc(true, e.target.value)}
defaultValue={"Question "+props.id}
inputProps = {{"maxlength": 40}}/>
<div class="question-text">
<TextField onChange = {e => questionOnInputFunc(false, e.target.value)} variant="outlined" fullWidth="true" label="Type your question"></TextField>
</div>
{mcqChoiceGeneratingFunc()}
</form>
</Paper>
);
}
export default McqQuestion;
The behavior I am describing can be seen in these screenshots.
The first two screenshots are expected. Two new questions were added and their respective objects were in the console log.
Expected Behavior at the start of the state
Expected behavior when two new questions were added
When question 1 was edited while questions 2 and 3 were there, the objects for question 3 disappeared.
Why is this happening and how do I fix this?
Issues
ExamArea
Storing react components in state is a React anti-pattern and sure-fire way to get yourself some stale state enclosures.
Store just the data in state and render the UI from it.
Any time you are updating react state that depends on the previous state (i.e. appending an element to an array, incrementing a count/id, etc...) you don't use a functional state update.
Use a functional state update to correctly update from any previous state versus state from the previous render cycle.
McqQuestion
Once I resolved your issues in ExamArea I was a bit thrown off by the usage of local_question_mcq and local_answerChoices_mcq. At first glance they appeared to be "state" that wasn't part of component state.
Limit the scope of utility variables such as local_question_mcq and local_answerChoices_mcq
Similar issues with the functional updates, but coupled to the overscoped local_question_mcq and local_answerChoices_mcq.
Use a functional state update to directly update packedQuestion in the onChange handlers.
Solution
ExamArea
Store only data in component state.
Map state to UI in render function.
Use functional state update to map previous state to next state. Use the question ID to match the question that needs to be updated and also shallow copy it.
Pass returnFromMcqQuestion as prop directly (not stored in state either).
Code:
function ExamArea(props) {
const [currentQuesID, setCurrentQuesID] = useState(2);
const [mcqQuestionList, setmcqQuestionList] = useState([{ id: 1 }]); // <-- store data only
function returnFromMcqQuestion(quesID, thisQuestion) {
setmcqQuestionList((mcqQuestionList) => // <-- functional state update
mcqQuestionList.map((question) =>
question.id === quesID // <-- shallow copy matching question
? {
...question,
...thisQuestion
}
: question
)
);
}
function generateMCQ(questionid) {
return {
id: questionid
};
}
function addAnotherQuestion() {
setmcqQuestionList((mcqQuestionList) => // <-- functional state update
mcqQuestionList.concat(generateMCQ(currentQuesID))
);
setCurrentQuesID((c) => c + 1); // <-- functional state update
}
return (
<div className="ExamArea">
{mcqQuestionList.map(({ id }) => (
<McqQuestion
key={id}
returnfunc={returnFromMcqQuestion} // <-- pass callback directly
id={id}
/>
))}
<button
onClick={addAnotherQuestion}
className="add_another_question_button"
>
+ Add Another Question
</button>
</div>
);
}
McqQuestion
Use functional state update to map previous state to next state.
Limit the scope of local_question_mcq and local_answerChoices_mcq, move them into fillUpQuestionWithDefault and declare them const.
Make code more DRY where possible.
Fix class vs className and other various React warnings.
Code:
function McqQuestion(props) {
const [packedQuestion, setPackedQuestion] = useState({});
useEffect(() => {
props.returnfunc(props.id, packedQuestion); // <-- update state in parent
}, [packedQuestion]);
function fillUpQuestionWithDefault() {
/*These two variables store a local copy of packedQuestion. These variables are first updated with the information from
onChange (or a variation of it), and then packedQuestion is set to an instance of this. */
const local_question_mcq = { // <-- provide initial values, then override
id: props.id,
title: `Question ${props.id}`,
};
const local_answerChoices_mcq = {};
function addOption(character, value = '') {
local_answerChoices_mcq[character] = value;
local_question_mcq["answer_choices"] = local_answerChoices_mcq;
}
function addQuestion(title, value) {
local_question_mcq[title ? "title" : "question_text"] = value; // <-- DRY
}
addQuestion(true, "Question " + props.id);
addQuestion(false, "");
['a', 'b', 'c', 'd'].forEach(c => addOption(c, '')); // <-- DRY
setPackedQuestion(local_question_mcq);
}
useEffect(() => {
fillUpQuestionWithDefault();
}, []);
function optionOnInputFunc(character, value) {
setPackedQuestion((question) => ({ // <-- functional state update
...question,
answer_choices: {
...question.answer_choices,
[character]: value
}
}));
}
function questionOnInputFunc(title, value) {
setPackedQuestion((question) => ({ // <-- functional state update
...question,
[title ? 'title' : 'question_text']: value
}));
}
function mcqChoiceGeneratingFunc() {
return (
<div className="Opt">
...
</div>
);
}
return (
<Paper className="Question">
...
</Paper>
);
}
When you are calling this function from child component then ques take the value of initial state in hook that is {}. Now you are adding key quesID in temp and updating the state. So it will be an expected behavior.
function returnFromMcqQuestion(prevQues, quesID, thisQuestion) {
var temp = {...prevQues};
temp["ques"+quesID] = thisQuestion;
setQues(prevQues);
}
So you need something like this.
<McqQuestion ques={ques} returnfunc={returnFromMcqQuestion} id={questionid}/>)
useEffect(()=> props.returnfunc(props.ques, props.id, packedQuestion));

Change handler for semantic-ui-react checkbox does not work : React+Typescript

I am having two semantic-ui-react checkboxes. When I am trying to attach change handlers, I get a value of 'undefined' when I console log .
Want to fetch both of the checkbox values.
Link to the sandbox: https://codesandbox.io/s/5vo8v4996k
Where am I going wrong?
Help would be appreciated
import React from "react";
import ReactDOM from "react-dom";
import { Checkbox } from "semantic-ui-react";
import Form from 'semantic-ui-react/dist/commonjs/collections/Form';
export default class App extends React.Component<{},{}> {
constructor(props:any) {
super(props);
this.state = {
cb1: true,
cb2: true
};
}
checkboxChangeHandler = (event: React.FormEvent<HTMLInputElement>) => {
let name = event.target.name;
console.log(name); // It is giving undefined here
if (name === "cb1") {
this.setState({ cb1: !this.state.cb1 });
}
if (name === "cb2") {
this.setState({ cb2: !this.state.cb2 });
}
};
render() {
return (
<div >
<Form>
<Checkbox
label={"CB1"}
name="cb1"
checked={this.state.cb1}
onChange={this.checkboxChangeHandler}
/>
<Checkbox
label={"CB2"}
checked={this.state.cb2}
name="cb2"
onChange={this.checkboxChangeHandler}
/>
</Form>
</div>
);
}
}
The way you have hooked up your event and the way you are accessing it is incorrect.
To fix it change:
onChange = {this.checkboxChangeHandler}
and
let name = event.target.name;
to:
onChange = {e => this.checkboxChangeHandler(e)}
and
const name = event.target.checked;
(Note that I've made "name" a const as you don't need to reassign its value in the function where you are using it)
Also note that you need to change the signature of your change handler from React.FormEvent to React.ChangeEvent i.e.
checkboxChangeHandler = (event: React.ChangeEvent<HTMLInputElement>)
You can see a working example here.
Got it working by using second param in callback, it contains all required information.
checkboxChangeHandler = (event: React.FormEvent<HTMLInputElement>, data: any) => {
this.setState({ [data.name]: value });
};
Working Sandbox: https://codesandbox.io/s/31oq13p3o1

Don't use constructor

In my code, I did not use constructor (). I've always seen people use the constructor in class components, but even though I'm not using it in that code, it's working perfectly. In my code, putting the state outside the constructor, is it a good idea or would it be better to use the constructor with the state set inside it? Can it give some sort of error in the future, or worsen my system's performance doing so? What is more advisable to do in this case?
import React, { Component, Fragment } from 'react'
import {Redirect} from 'react-router-dom'
import { connect } from 'react-redux'
import ActionCreator from '../redux/actionCreators'
import Button from '../elements/Button'
const statsgenre = {
'Ação': 'Action',
'Comédia': 'Comedy',
'Drama': 'Drama'
}
const statsuser = {
'Assistido' : 'Watched',
'Assistindo': 'Watching',
'Assistir': 'Watch'
}
class ScreensEditSeries extends Component{
state = {
id: '',
name: '',
status: '',
genre: '',
notes: ''
}
componentDidMount = () => {
const serie = {...this.props.match.params}
this.props.load(serie)
this.props.reset()
}
static getDerivedStateFromProps(newProps, prevState){
let serie = {}
if (prevState.name === '' || prevState.name === undefined){
if (newProps.series.serie.name !== prevState.name){
serie.name = newProps.series.serie.name
}
if (newProps.series.serie.genre !== prevState.genre){
serie.genre = newProps.series.serie.genre
}
if (newProps.series.serie.status !== prevState.status){
serie.status = newProps.series.serie.status
}
if (newProps.series.serie.notes !== prevState.notes){
serie.notes = newProps.series.serie.notes
}
return serie
}
}
saveSeries = () => {
const {name, status, genre, notes} = this.state
const id = this.props.match.params.id
const newSerie = {
id,
name,
status,
genre,
notes
}
this.props.save(newSerie)
}
handleChange = field => event => {
this.setState({[field] : event.target.value})
}
render(){
return (
<Fragment>
<div className="container">
<div>
{this.props.series.saved && <Redirect to={`/series/${this.props.match.params.genre}`}/>}
<h1 className='text-white'>Edit Série</h1>
{!this.props.series.isLoadding && <Button>
Name: <input type="text" value={this.state.name} onChange={this.handleChange('name')} className="form-control" /><br />
Status: {<span> </span>}
<select value={this.state.status} onChange={this.handleChange('status')}>
{Object.keys(statsuser)
.map( key => <option key={key}>{statsuser[key]}</option>)}
</select><br/><br/>
Genre: {<span> </span>}
<select value={this.state.genre} onChange={this.handleChange('genre')}>
{Object.keys(statsgenre)
.map(key => <option key={key}>{statsgenre[key]}</option>)}
</select><br/><br/>
Notes: <textarea type='text' value={this.state.notes} onChange={this.handleChange('notes')} className="form-control"></textarea><br />
<button className="button button2" type="button" onClick={this.saveSeries}>Save</button>
</Button>}
{this.props.series.isLoadding && <p className='text-info'>Loading...</p>}
</div>
</div>
</Fragment>
)
}
}
const mapStateToProps = state => {
return {
series: state.series
}
}
const mapDispatchToProps = dispatch => {
return {
load : serie => dispatch(ActionCreator.getSerieRequest(serie)),
save: newSerie => dispatch(ActionCreator.updateSerieRequest(newSerie)),
reset : () => dispatch(ActionCreator.seriesReset()),
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ScreensEditSeries)
In general, you should only use a constructor if you need logic when the class is first created, or if your setup depends on the props passed in. Since everything in your initial state is hardcoded not using a constructor is fine in this case.
There is no problem in using class components without a constructor. Usually you need it in case you have to do some work to prepare the state, process some props or other setup some instance variables as soon as the component is instantiated.
It's ok :)
Here, instead, there is a very interesting post from Dan Abramov about why, if you need to use the constructor, is needed to call super(props):
https://overreacted.io/why-do-we-write-super-props/
Not super related to the question, but asking about constructor, I thought it could be useful to you.
There's no difference. The reason you see most people doing it inside of the constructor is because doing state = {} directly on the class is new syntax that hasn't been widely adopted yet (it often still requires a Babel or similar transformation). See proposal-class-fields for more information on it. One thing to note is that if you need to access any props to initialize the state, you have to do that in the constructor.

Categories

Resources