Update state when data changed in React+Redux - javascript

I'm too new to react. I'm curious about a few things. The first topic I was wondering, why the HTML tags in js?
I need to do a project. I have a method that returns json with .NET
I have a code like below. How do I update the div when I add something into it?
This .net code.
private static readonly IList<Mock.Model.Skills> _Skills;
[Route("api/Skills/add")]
[HttpPost]
public ActionResult Skills(Mock.Model.Skills Model)
{
if (ModelState.IsValid)
{
_Skills.Add(Model);
return Json("true");
}
return Json(false);
}
And, js (react) code.
var Rows = React.createClass({
render: function () {
return (
<span className="label label-info tags">{this.props.item.tag}</span>
);
}
});
var SkillsRow = React.createClass({
getInitialState: function () {
return {
items: []
}
},
componentDidMount: function () {
$.get(this.props.dataUrl, function (data) {
if (this.isMounted()) {
this.setState({
items: data
});
}
}.bind(this));
},
render: function () {
var rows = [];
this.state.items.forEach(function (item, index) {
rows.push(<Rows class="label label-info tags" key={index} item={item} />);
});
return (<span>{rows}</span>);
}
});
ReactDOM.render(
<SkillsRow dataUrl="/api/Skills" />,
document.getElementById('skills-data')
);
This works well, but do not add.
I wonder if this is the correct method?
Thank you to everyone who showed interest.

If you want to add items to api, you can call something like this:
var SkillsRow = React.createClass({
getInitialState: function() {
return {
items: [],
currentEditor: ''
}
},
componentDidMount: function() {
this.updateSkillList()
},
updateSkillList: function() {
$.get(this.props.dataUrl, function(data) {
this.setState({
items: data
})
}).bind(this)
},
handleEditorChange: function(event) {
this.setState({
currentEditor: event.target.value
})
},
handlePostForm: function() {
$.post('api/Skills/add', {skill: this.state.currentEditor}, function(data) {
this.updateSkillList()
})
},
renderSkillList: function() {
this.state.items.map(function(item, idx) {
return <Row className="label label-info tags" key={idx} item={item} />
})
},
render: function() {
return (
<div>
<span>
<input value={this.state.currentEditor} onChange={this.handleEditorChange} />
<button onClick={this.handlePostForm} />
</span>
<span>{this.renderSkillList()}</span>
</div>
)
}
})
Edited:
Now i understood the question, you code will look something like this, also you will have to fix backend code to only receive the skill name, and then create the object (you can't create a C# object in javascript)

Related

React - not repeat a component

I have the following react component for a dropdown:
var UIDropdown = React.createClass({
getDefaultProps: function () {
return {
isOpen: false
};
},
render: function () {
if (this.props.isOpen) {
return (
<div className="dropdown">
<ul className="uk-nav uk-nav-dropdown tm-svg-center">
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this) }
</ul>
</div>
);
}
return null;
}
});
I'm looping through some data which outputs some list items, but I have a number for different data items.
How can I add the following in the component without repeating the dropdown component code:
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this) }
Example but with a single dropdown component
https://jsfiddle.net/zidski/ddLdg84s/
If I understand you correctly, you need to reuse your Dropdown component
Then do something like this
DropdownItems component
var DropdownItems = React.createClass({
render: function () {
return(
<ul className="uk-nav uk-nav-dropdown tm-svg-center">
{this.props.mapOpacityValues.map(function (list, i) {
return (
<li onClick={this.props.opacityThermatic.bind(this, list) } key={"list" + i}>{`${list * 100}%`}</li>
);
}, this)
}
</ul>
)
}
});
UIDropdown component
var UIDropdown = React.createClass({
getDefaultProps: function () {
return {
isOpen: false
};
},
render: function () {
if (this.props.isOpen) {
return (
<div className="dropdown">
{this.props.children}
</div>
);
}
return null;
}
});
Then you can create any number UIDropdowns like
<UIDropdown>
<DropdownItems mapOpacityValues={someData} opacityThermatic={someFunction}>
</UIDropdown>
Here you need to repeat neither dropdown nor li items. You just resue them in your implementation.

Listview not working... (Objects are not valid as React Child)

I am currently building an app in which I am trying to implement the React Native Listview functionality. I am however at a standstill...
The code below yields simply the error: Objects are not valid as React Child (found: objects with keyes {name, img, .... } )
var ComponentOne = React.createClass({
getInitialState: function() {
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
loaded: false;
return {
dataSource: ds.cloneWithRows(this.props.friendFeed),
};
},
render: function() {
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.CardViewer}
style={styles.card} />
)
},
CardViewer(rowData, sectionID, rowID) {
console.log(rowData.friend);
return (
<CardView
name={rowData.friend}
fullname='xyz'
distance='xyz'
title={rowData.post}
message={rowData.post}
score='xyz'
stars='xyz'
starcolors={colors.General.black}
vouched="Example" />
)
}
})
But if I instead try to write the Cardviewer as: ... <CardView name={rowData.friend.name} ... it will return the error that undefined is not an object. But I dont know how to further set some loading state on each of those...
I create the data that I use in the following manner:
var Home = React.createClass({
getInitialState: function() {
return {
componentSelected: 'One',
tokenSupreme: 'Loading big token...',
userName: "Loading...",
friendFeed: 'Loading...',
};
loaded: false;
},
componentDidMount: function() {
Method.loginUser(AccessToken)
.then((res) => this.setState({
userName: JSON.parse(res).user.name,
tokenSupreme: JSON.parse(res).token,
}))
.catch((error) => console.log(error))
.done();
loaded: true;
exports.tokenSupreme = this.state.tokenSupreme;
},
changeComponent: function(component) {
Method.getFriendFeed(this.state.tokenSupreme)
.then((res) => this.setState({
friendFeed: JSON.parse(res).friendPosts,
}))
.catch((error) => console.log(error))
.done();
this.setState({
componentSelected: component
})
},
renderComponent: function(component) {
if(component === 'One') {
return <ComponentOne friendFeed={this.state.friendFeed} />
} else if(component === 'Two') {
return <ComponentTwo />
}
},
Where have I gone wrong? My guess is because that I dont predefine som state before loading which throws the object not defined, but then again, the Listview does not seem to have that as an option, or then again, I have (most likely) probably misintepreted it. So, please help! :)
EDIT:
Trying to manipulate the execution order via the component-lifecycles I made it so that loaded = true when the frienFeed is executed, and by then I have my render as an if function so that it renders "loading" untill otherwise. But it never seems to re-evaluate the if statement. Because I can see in my log how loaded = true, but it does not react. Code as the following in the ComponentOne:
render: function() {
if (this.state.loaded != true) {
return this.renderLoadingView();
} else if(this.state.loaded === true) {
console.log('trying...');
console.log(this.state.props.friendFeed);
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
style={styles.card} />
)
}
},

React render has the correct data but won't render the JSX

So, I believe this is a formatting issue OR I'm not clear about how the return works when dynamically building.
The render function in Results works, if I replace the code with anythign else it renders where I want. Similarly, the console.log's in the Results function outputs the data correctly. There's no error, it just doesn't render the html and it doesn't hit the debugger in SynonymElement.
What am I missing in here / what core concept am I misconstruing?
(This is just an input form that takes a word, user hits submit, it returns an object with the word as a key and the value an array of synonynms. that get rendered in the ul)
'use strict'
const Smithy = React.createClass({
dsiplayName: "Smithy",
getInitialState: function() {
return { data: []};
},
handleSubmit: function(data) {
$.get('/get-synonyms', { data: data.data }).done(function(data) {
this.setState({ data: data})
}.bind(this));
},
render: function() {
return (
<div className="smithy">
<h1>Craft Tweet</h1>
<SmithyForm onSubmit={this.handleSubmit} />
<Results data={this.state.data} />
</div>
)
}
})
const SmithyForm = React.createClass({
displayName: "SmithyForm",
getInitialState: function() {
return { placeholder: "tweet", value: "" };
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
handleSubmit: function(event) {
event.preventDefault();
var tweet = this.state.value.trim();
this.props.onSubmit({ data: tweet });
this.setState({value: ''});
},
render: function() {
var placeholder = this.state.placeholder;
var value = this.state.value;
return (
<form className="smithyForm" onSubmit={this.handleSubmit}>
<input type="text" placeholder={placeholder} value={value} onChange={this.handleChange} />
<button>smithy</button>
</form>
);
}
})
const SynonymElement = React.createClass({
render: function() {
debugger
return (
<li>{this.props.data}</li>
)
}
})
const Results = React.createClass({
render: function() {
var words = this.props.data;
return (
<div className="results">
{
Object.keys(words).map(function(value) {
{ console.log(value) }
<div className={value}>
<ul>
{
words[value].map(function(syn) {
{ console.log(syn) }
return <SynonymElement data={syn} />
})
}
</ul>
</div>
})
}
</div>
)
}
})
ReactDOM.render(<Smithy />, document.getElementsByClassName('container')[0])
Might have some other complicating issues but assuming everything else is wired up correctly, you need to return the result of the function you pass into the first map (over the collection Object.keys(words)) just as you have for the later map otherwise the function is executed and nothing useful is returned.
Possibly just a dupe of loop inside React JSX
return (
<div className="results">
{
Object.keys(words).map(function(value) {
return ( // <-- this
<div className={value}>

React - State not updated

Here I try to set state.autocomplete to 'hello' and then print it, but state seems to be null. How can that be when I just updated the state using setState? data is set as a global variable.
var data = {
populate_at: ['web_start', 'web_end'],
autocomplete_from: ['customer_name', 'customer_address']
};
var AutocompleteFromCheckboxes = React.createClass({
handleChange: function(e) {
this.setState( { autocomplete_from: 'event.target.value' } );
console.log('autocompleteFrom state: ', this.state.autocomplete_from);
// ^ => Uncaught TypeError: Cannot read property 'autocomplete_from' of null
return 1;
},
render: function() {
var autocompleteFrom = this.props.autocomplete_from.map(function(value) {
return (
<label for={value}>
<input type="checkbox" name={value} value="{value}"
onChange={this.handleChange.bind(this)}
ref="autocomplete-from"/>
{value}
</label>
);
}, this);
return (
<div className="autocomplete-from">
{autocompleteFrom}
</div>
);
}
});
var DynamicForm = React.createClass({
getInitialState: function() {
return {
name : null,
populate_at : null,
same_as : null,
autocomplete_from : "not set",
title : null
};
},
saveAndContinue: function(e) {
e.preventDefault();
var data = {
name : this.refs.name.getDOMNode().value,
};
console.log('data: ' + data.name);
},
render: function() {
return (
<AutocompleteFromCheckboxes
autocomplete_from={this.props.data.autocomplete_from} />
);
}
});
var mountpoint = document.getElementById('dynamic-form');
if ( mountpoint ) {
React.render(<DynamicForm data={data} />, mountpoint);
}
});
From the reactjs docs:
setState() does not immediately mutate this.state but creates a pending state transition. Accessing this.state after calling this method can potentially return the existing value.
https://facebook.github.io/react/docs/component-api.html
What you can do is pass a callback function to setState which is triggered once the state has been updated:
this.setState(
{autocomplete_from: ...},
function () {
... at this point the state of the component is set ...
}
)
You need to set the initial state of your component, try adding the following to the top of your component.
getInitialState: function() {
return {
autocomplete_from: ''
};
}
EDIT:
In your DynamicFrom component you have:
render: function() {
return (
<AutocompleteFromCheckboxes
autocomplete_from={this.props.data.autocomplete_from} />
);
}
Since you are trying to reference the state you should write
autocomplete_form={this.state.autocomplete_from}
Also you are trying to set the state from a child component and it should not directly modify state. The best way to approach this is to pass down a function from DynamicFrom(holds the state) to AutocompleteFromCheckboxes. Like so.
var DynamicForm = React.createClass({
handleChange: function(value) {
this.setState({autocompelete_from: value});
},
render: function() {
return(
<AutocompleteFromCheckboxes
autocomplete_from={this.state.autocomplete_from}
handleChange={this.handleChange}
/>
);
},
....
});
Then call that function in your child component
AutocompleteFromCheckboxes = React.createClass({
....
onChange={this.handleChange}
....
handleChange: function(e) {
this.props.handleChange(e.target.value);
}
});
To see updated state value after doing setState you should do something like below
this.setState( { autocomplete_from: 'event.target.value' }, () => {
console.log(this.state.autocomplete_from);//this will print the updated state value
});

Filtering in Reactjs / Creating filter buttons

I am trying to creating some reusable components to filter arrays, but I think I am doing something wrong.
Should I be passing the handleclick all the way back up the chain of components like this?
I also cannot get the loading icon to appear in the filter button, it seems the button only re-renders after the click and filtering has been completed.
Is there a better place to store the active button, but this is the only way I could get the buttons to re-render.
var FilterButton = React.createClass({
getInitialState: function() {
return { loading: false };
},
handleClick: function() {
this.setState({ loading: true }, function() {
this.props.handleClick(this.props.filter);
});
this.setState({ loading: false });
},
render: function() {
var cx = React.addons.classSet;
var classes = cx({
'btn': true,
'btn-white': !this.props.active,
'btn-primary': this.props.active
});
var loader = <i className="fa fa-circle-o-notch fa-spin"></i>;
return (
<button className={classes} onClick={this.handleClick}>
{this.state.loading ? loader : ''} {this.props.label}
</button>
);
}
});
var FilterBar = React.createClass({
getInitialState: function() {
return { filter: 1 };
},
handleClick: function(filter) {
this.setState({ filter: filter }, function() {
this.props.handleClick(this.state.filter);
});
},
render: function() {
var filter = this.state.filter;
return (
<div className="nav">
<FilterButton handleClick={this.handleClick} active={filter == 1} filter="1" label="Pending" />
<FilterButton handleClick={this.handleClick} active={filter == 2} filter="2" label="Canceled" />
<FilterButton handleClick={this.handleClick} active={filter == 3} filter="3" label="Shipped" />
</div>
);
}
});
var OrdersView = React.createClass({
getInitialState: function () {
return {orders: [], status_id: 1};
},
componentDidMount: function() {
/* get orders here via ajax and set state*/
},
handleFilter: function(status_id) {
this.setState({ status_id: status_id });
},
render: function() {
var self = this;
var orders = $.grep(this.state.orders, function(order, i){
return order.status_id == self.state.status_id;
});
return (
<div>
<FilterBar handleClick={this.handleFilter} />
<OrderList orders={orders} />
</div>
);
}
});

Categories

Resources