Reactjs submitHandler if the state is set - reactjs

I am new to reactjs - I've tried setting the state if checkbox get selected - and when I read the state I can see the state gets populated console.log('state' ,state) - gives {'option1': true} -- but when I do this.state.length its undefined.

Reason is very simple on: State is an object that's why length is giving undefined.
If you want to check how many key-value pairs are present then use Object.keys, it will return an array of all the keys then use length on that.
Like this:
console.log(Object.keys(this.state).length).
Check this snippet:
let obj = {'option1': true, 'option2': true, 'option3': true};
console.log(Object.keys(obj).length);

Related

Material UI Select not showing options

I have a Component where in the componentDidMount method I fetch information from the backend and put it on the state of my component. However I have to change the response in order to use the objects coming from the backend on the Select Component from material UI.
I do it like this:
var toAdd = []
axios.get(...).then(response.data.forEach(p => toAdd.push({id: p.name, value: p.name}))})
...
this.setState({schemas: toAdd})
Then, on render method I send schemas from state to the form component. The form itself has a set of inputfields with the select component as well.
I have the following warning:
Material-UI: You have provided an out-of-range value undefined for the select (name="schema") component.
Consider providing a value that matches one of the available options or ''.
The available values are "".
I did console.log and the first value I get is an array [] but with objects inside. After I write something on the input fields, the array changes to [{...}] and then the Select can show the options I wanted. The first array [] is not empty, if I open it on console there is one object inside. The same goes for [{...}]. Is there something I am doing wrong?
why don't you use the component state in order to get the data at the time when you get it from the API like this.
state={toAdd:[]}
then while fetching data you just set your state like this
this.setState({toAdd:... response.data.map(v=> {return{id:v.name,value:v.value}})

Store checkbox values as array in React

I have created the following demo to help me describe my question: https://codesandbox.io/s/dazzling-https-6ztj2
I have a form where I submit information and store it in a database. On another page, I retrieve this data, and set the checked property for the checkbox accordingly. This part works, in the demo this is represented by the dataFromAPI variable.
Now, the problem is that when I'd like to update the checkboxes, I get all sorts of errors and I don't know how to solve this. The ultimate goal is that I modify the form (either uncheck a checked box or vice versa) and send it off to the database - essentially this is an UPDATE operation, but again that's not visible in the demo.
Any suggestions?
Also note that I have simplified the demo, in the real app I'm working on I have multiple form elements and multiple values in the state.
I recommend you to work with an array of all the id's or whatever you want it to be your list's keys and "map" on the array like here https://reactjs.org/docs/lists-and-keys.html.
It also helps you to control each checkbox element as an item.
Neither your add or delete will work as it is.
Array.push returns the length of the new array, not the new array.
Array.splice returns a new array of the deleted items. And it mutates the original which you shouldn't do. We'll use filter instead.
Change your state setter to this:
// Since we are using the updater form of setState now, we need to persist the event.
e.persist();
setQuestion(prev => ({
...prev,
[e.target.name]: prev.topics.includes(e.target.value)
// Return false to remove the part of the array we don't want anymore
? prev.topics.filter((value) => value != e.target.value)
// Create a new array instead of mutating state
: [...prev.topics, e.target.value]
}));
As regard your example in the codesandbox you can get the expected result using the following snippet
//the idea here is if it exists then remove it otherwise add it to the array.
const handleChange = e => {
let x = data.topics.includes(e.target.value) ? data.topics.filter(item => item !== e.target.value): [...data.topics, e.target.value]
setQuestion({topics:x})
};
So you can get the idea and implement it in your actual application.
I noticed the problem with your code was that you changed the nature of question stored in state which makes it difficult to get the attribute topics when next react re-renders Also you were directly mutating the state. its best to alway use functional array manipulating methods are free from side effects like map, filter and reduce where possible.

Redux-From getFormValues() returning undefined when values are in Fields

I need to use the values from state to make dynamic fields appear.
I have the below code:
{jobSpec &&
this.renderRows(form, form.dependencies.jobSpec[jobSpec[0].id])}
const mapStateToProps = (state) => ({
formData: state.formData,
jobSpec: selector(state, 'jobSpec'),
values: getFormValues('formWizard')(state),
});
The field named jobSpec causes more fields to load depending on what the value is, in the first part of the code.
The forms will be created with JSON and I will not know that names of all fields or their values, so I need to loop through the values in state and check if a new field should be loaded whenever state changes.
I added getFormValues() to get the values on the form. However Values are always undefined no matter what I enter into the form fields.
So either this function is not being called or it's not updating with state change.
Does anyone have experience with this?
Well it appears that "values" is being used elsewhere. When I change it to:
formValues: getFormValues('formWizard')(state),
The issue was resolved.

React: setting state and default input from prop

I'm creating a app that allows users to create assessments (that other users can complete). Right now I am working on an 'edit' page, where a users loads a form that is prefilled with the relevant data - but he is then able to change these values.
However, I am having trouble with two things (that I suspect are related).
First: the input fields wont display a default value that is derived from the component state.
Second: If I set the input fields directly from the props I am no longer able to change the values.
The components gets passed a prop that is called block_data which is a dict containing key/value pairs of strings.
I'm attempting to convert load it into the state like so
constructor(props) {
super(props);
this.state = {
block: this.props.block_data,
question_list: [],
question_options: ['BO', 'SC', 'SR', 'NO'],
block_list: [],
};
(..)
}
However, this does not work. When I check in the chrome react extension the state is not set.
The input fields are all very simular to the example I've included below. Here I've set its value from the props. In this case it does display the correct initial data. But I am unable to edit it.
<input
onChange={e => this.changeIsANaturalPartOfLife(e)}
value={this.props.block_data.title}
name="title"
/>
Below is the 'on change' function. When I check the chrome react tool, I can see that only the first letter of the state is updated when I start typing. The input field does not show any changes.
changeIsANaturalPartOfLife(e, optional) {
const target = e.target;
const name = target.name;
const value = target.value;
console.log(value);
this.setState({ block: {[name]: value }});
}
I am really at a loss here on what to do. What I am trying to do here seems simple enough, yet I'm unable to advance beyond this flawed stage. Does anyone have an idea what I am doing wrong?
As you mentioned in comment: "the data is loaded from a DjangoRestAPI".
Solution of first problem:
You need to use componentwillreceiveprops lifecycle method to update the state with new props values (after successfully fetched from server) otherwise state of child component will always have the initial data of parent component.
As per DOC:
componentWillReceiveProps() is invoked before a mounted component
receives new props. If you need to update the state in response to
prop changes (for example, to reset it), you may compare this.props
and nextProps and perform state transitions using this.setState() in
this method.
Use this method:
componentwillreceiveprops(nextProps) {
// compare nextProps.block_data and this.state.block if not equal
this.setState({
block: nextProps.block_data
})
}
Solution of second problem:
When you are directly using the props instead of storing into state, then you need to update the value in parent component during onChange, because you are using this.props.value and updating this.state.value, and hence props.value will always be same and it will not allow you to type anything.

How to update array within state object with react/redux

In my reducer i have this state:
const initialState = fromJS({
resources: false,
testval: [0, 0, 0, 0],})
I want to append or remove array values for testval when my action is fired. I have immutable, and immutability-helper imported but im struggling with the syntax to get this to work.
For example this isnt working - the state isnt changing:
return update(state, {
testval: {
$set: 'test'
}
});
It looks like you might be mixing up two different toolsets. Immutable.js is a specialized set of data structures, while the Immutability-Helper library expects to work on plain JS objects.
You might want to read through the Immutable Update Patterns section of the Redux docs, which discusses ways to properly do immutable updates on plain JS data, as well as the related links in the Prerequisite Concepts docs page.
Ok i figured this out using Immutable.
Add to array:
return state.updateIn(['showtask'], arr => arr.push(action.userid))
Remove from array:
return state.updateIn(['showtask'], arr => arr.splice(arr.indexOf(action.userid),1))
its because you are updating it wrong way,
1st thing is your array will be converted to List object, so that need to be updated in list style .
in below example 1 is the index i am updating, you can use any dynamic variable for this, also item is the current value at that index. if that is object(in some other use case) you can modify the object and return it.
const initialState = Immutable.fromJS({
resources: false,
testval: [0, 0, 0, 0]});
//replace initial state with state, i just posted example code
initialState = initialState.set("testval",initialState.get("testval").update(1,(item)=>{
return 2;
}));
console.log(initialState.get("testval"))
for more detailed example you can also check this post https://onl9class.com/using-immutable-js/

Resources